1 /*< ilib.js */
  2 /*
  3  * ilib.js - define the ilib name space
  4  * 
  5  * Copyright © 2012-2015, JEDLSoft
  6  *
  7  * Licensed under the Apache License, Version 2.0 (the "License");
  8  * you may not use this file except in compliance with the License.
  9  * You may obtain a copy of the License at
 10  *
 11  *     http://www.apache.org/licenses/LICENSE-2.0
 12  *
 13  * Unless required by applicable law or agreed to in writing, software
 14  * distributed under the License is distributed on an "AS IS" BASIS,
 15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 16  *
 17  * See the License for the specific language governing permissions and
 18  * limitations under the License.
 19  */
 20 
 21 /**
 22  * @namespace The global namespace that contains general ilib functions useful
 23  * to all of ilib
 24  * 
 25  * @version "12.0.003"
 26  */
 27 var ilib = ilib || {};
 28 
 29 /** @private */
 30 ilib._ver = function() {
 31     return "12.0.003"
 32     ;
 33 };
 34 
 35 /**
 36  * Return the current version of ilib.
 37  * 
 38  * @static
 39  * @return {string} a version string for this instance of ilib
 40  */
 41 ilib.getVersion = function () {
 42 	// TODO: need some way of getting the version number under dynamic load code
 43     return ilib._ver() || "12.0"; 
 44 };
 45 
 46 /**
 47  * Place where resources and such are eventually assigned.
 48  */
 49 ilib.data = {
 50 	/** @type {{ccc:Object.<string,number>,nfd:Object.<string,string>,nfc:Object.<string,string>,nfkd:Object.<string,string>,nfkc:Object.<string,string>}} */
 51     norm: {
 52     	ccc: {},
 53     	nfd: {},
 54     	nfc: {},
 55     	nfkd: {},
 56     	nfkc: {}
 57     },
 58     zoneinfo: {
 59         "Etc/UTC":{"o":"0:0","f":"UTC"},
 60         "local":{"f":"local"}
 61     },
 62     /** @type {Object.<string,{to:Object.<string,string>,from:Object.<string,number>}>} */ charmaps: {},
 63     /** @type {null|Object.<string,Array.<Array.<number>>>} */ ctype: null,
 64     /** @type {null|Object.<string,Array.<Array.<number>>>} */ ctype_c: null,
 65     /** @type {null|Object.<string,Array.<Array.<number>>>} */ ctype_l: null,
 66     /** @type {null|Object.<string,Array.<Array.<number>>>} */ ctype_m: null,
 67     /** @type {null|Object.<string,Array.<Array.<number>>>} */ ctype_p: null,
 68     /** @type {null|Object.<string,Array.<Array.<number>>>} */ ctype_z: null,
 69     /** @type {null|Object.<string,Array.<Array.<number>>>} */ scriptToRange: null,
 70     /** @type {null|Object.<string,string|Object.<string|Object.<string,string>>>} */ dateformats: null,
 71     /** @type {null|Array.<string>} */ timezones: []
 72 };
 73 
 74 /*
 75 if (typeof(window) !== 'undefined') {
 76     window["ilib"] = ilib;
 77 }
 78 */
 79 
 80 // export ilib for use as a module in nodejs
 81 if (typeof(module) !== 'undefined') {
 82     
 83     module.exports.ilib = ilib;  // for backwards compatibility with older versions of ilib
 84 }
 85 
 86 /**
 87  * Sets the pseudo locale. Pseudolocalization (or pseudo-localization) is used for testing
 88  * internationalization aspects of software. Instead of translating the text of the software
 89  * into a foreign language, as in the process of localization, the textual elements of an application
 90  * are replaced with an altered version of the original language.These specific alterations make
 91  * the original words appear readable, but include the most problematic characteristics of 
 92  * the world's languages: varying length of text or characters, language direction, and so on.
 93  * Regular Latin pseudo locale: eu-ES and RTL pseudo locale: ps-AF
 94  * 
 95  * @param {string|undefined|null} localename the locale specifier for the pseudo locale
 96  */
 97 ilib.setAsPseudoLocale = function (localename) {
 98    if (localename) {
 99 	   ilib.pseudoLocales.push(localename)
100    }
101 };
102 
103 /**
104  * Reset the list of pseudo locales back to the default single locale of zxx-XX.
105  * @static
106  */
107 ilib.clearPseudoLocales = function() {
108 	ilib.pseudoLocales = [
109         "zxx-XX",
110         "zxx-Cyrl-XX",
111         "zxx-Hans-XX",
112         "zxx-Hebr-XX"
113     ];
114 };
115 
116 ilib.clearPseudoLocales();
117 
118 /**
119  * Return the name of the platform
120  * @private
121  * @static
122  * @return {string} string naming the platform
123  */
124 ilib._getPlatform = function () {
125     if (!ilib._platform) {
126     	try {
127     		if (typeof(java.lang.Object) !== 'undefined') {
128     			ilib._platform = (typeof(process) !== 'undefined') ? "trireme" : "rhino";
129     			return ilib._platform;
130     		}
131     	} catch (e) {}
132     	
133         if (typeof(process) !== 'undefined' && typeof(module) !== 'undefined') {
134             ilib._platform = "nodejs";
135         } else if (typeof(Qt) !== 'undefined') {
136         	ilib._platform = "qt";
137         } else if (typeof(window) !== 'undefined') {
138             ilib._platform = (typeof(PalmSystem) !== 'undefined') ? "webos" : "browser";
139         } else {
140             ilib._platform = "unknown";
141         }
142     }    
143     return ilib._platform;
144 };
145 
146 /**
147  * If this ilib is running in a browser, return the name of that browser.
148  * @private
149  * @static
150  * @return {string|undefined} the name of the browser that this is running in ("firefox", "chrome", "ie", 
151  * "safari", or "opera"), or undefined if this is not running in a browser or if
152  * the browser name could not be determined 
153  */
154 ilib._getBrowser = function () {
155 	var browser = undefined;
156 	if (ilib._getPlatform() === "browser") {
157 		if (navigator && navigator.userAgent) {
158 			if (navigator.userAgent.indexOf("Firefox") > -1) {
159 				browser = "firefox";
160 			}
161 			if (navigator.userAgent.indexOf("Opera") > -1) {
162 				browser = "opera";
163 			}
164 			if (navigator.userAgent.indexOf("Chrome") > -1) {
165 				browser = "chrome";
166 			}
167 			if (navigator.userAgent.indexOf(" .NET") > -1) {
168 				browser = "ie";
169 			}
170 			if (navigator.userAgent.indexOf("Safari") > -1) {
171 				// chrome also has the string Safari in its userAgent, but the chrome case is 
172 				// already taken care of above
173 				browser = "safari";
174 			}
175 		}
176 	}
177 	return browser;
178 };
179 
180 /**
181  * Return the value of a global variable given its name in a way that works 
182  * correctly for the current platform.
183  * @private
184  * @static
185  * @param {string} name the name of the variable to return
186  * @return {*} the global variable, or undefined if it does not exist
187  */
188 ilib._global = function(name) {
189     switch (ilib._getPlatform()) {
190         case "rhino":
191             var top = (function() {
192               return (typeof global === 'object') ? global : this;
193             })();
194             break;
195         case "nodejs":
196         case "trireme":
197             top = typeof(global) !== 'undefined' ? global : this;
198             //console.log("ilib._global: top is " + (typeof(global) !== 'undefined' ? "global" : "this"));
199             break;
200         case "qt":
201         	return undefined;
202         default:
203         	top = window;
204         	break;
205     }
206     try {
207 		return top[name];
208 	} catch (e) {
209 		return undefined;
210 	}
211 };
212 
213 /**
214  * Return true if the global variable is defined on this platform.
215  * @private
216  * @static
217  * @param {string} name the name of the variable to check
218  * @return {boolean} true if the global variable is defined on this platform, false otherwise
219  */
220 ilib._isGlobal = function(name) {
221 	return typeof(ilib._global(name)) !== 'undefined';
222 };
223 
224 /**
225  * Sets the default locale for all of ilib. This locale will be used
226  * when no explicit locale is passed to any ilib class. If the default
227  * locale is not set, ilib will attempt to use the locale of the
228  * environment it is running in, if it can find that. If not, it will
229  * default to the locale "en-US". If a type of parameter is string, 
230  * ilib will take only well-formed BCP-47 tag  <p>
231  * 
232  * 
233  * @static
234  * @param {string|undefined|null} spec the locale specifier for the default locale
235  */
236 ilib.setLocale = function (spec) {
237     if (typeof(spec) === 'string' || !spec) {
238         ilib.locale = spec;
239     }
240     // else ignore other data types, as we don't have the dependencies
241     // to look into them to find a locale
242 };
243 
244 /**
245  * Return the default locale for all of ilib if one has been set. This 
246  * locale will be used when no explicit locale is passed to any ilib 
247  * class. If the default
248  * locale is not set, ilib will attempt to use the locale of the
249  * environment it is running in, if it can find that. If not, it will
250  * default to the locale "en-US".<p>
251  * 
252  * 
253  * @static
254  * @return {string} the locale specifier for the default locale
255  */
256 ilib.getLocale = function () {
257     if (typeof(ilib.locale) !== 'string') {
258     	var plat = ilib._getPlatform();
259     	switch (plat) {
260     		case 'browser':
261             	// running in a browser
262                 ilib.locale = navigator.language.substring(0,3) + navigator.language.substring(3,5).toUpperCase();  // FF/Opera/Chrome/Webkit
263                 if (!ilib.locale) {
264                     // IE on Windows
265                     var lang = typeof(navigator.browserLanguage) !== 'undefined' ? 
266                         navigator.browserLanguage :
267                         (typeof(navigator.userLanguage) !== 'undefined' ? 
268                             navigator.userLanguage :
269                             (typeof(navigator.systemLanguage) !== 'undefined' ?
270                                 navigator.systemLanguage :
271                                 undefined));
272                     if (typeof(lang) !== 'undefined' && lang) {
273                         // for some reason, MS uses lower case region tags
274                         ilib.locale = lang.substring(0,3) + lang.substring(3,5).toUpperCase();
275                     }
276                 }
277                 break;
278     		case 'webos':
279                 // webOS
280                 if (typeof(PalmSystem.locales) !== 'undefined' && 
281                 		typeof(PalmSystem.locales.UI) != 'undefined' && 
282                 		PalmSystem.locales.UI.length > 0) {
283                     ilib.locale = PalmSystem.locales.UI;
284                 } else if (typeof(PalmSystem.locale) !== 'undefined') {
285                 	ilib.locale = PalmSystem.locale;
286                 }
287     			break;
288     		case 'rhino':
289                 if (typeof(environment) !== 'undefined' && environment.user && typeof(environment.user.language) === 'string' && environment.user.language.length > 0) {
290                 	// running under plain rhino
291                     ilib.locale = environment.user.language;
292                     if (typeof(environment.user.country) === 'string' && environment.user.country.length > 0) {
293                         ilib.locale += '-' + environment.user.country;
294                     }
295                 }
296                 break;
297     		case "trireme":
298             	// under trireme on rhino emulating nodejs
299             	var lang = process.env.LANG || process.env.LANGUAGE || process.env.LC_ALL;
300                 // the LANG variable on unix is in the form "lang_REGION.CHARSET"
301                 // where language and region are the correct ISO codes separated by
302                 // an underscore. This translate it back to the BCP-47 form.
303                 if (lang && typeof(lang) !== 'undefined') {
304                     ilib.locale = lang.substring(0,2).toLowerCase() + '-' + lang.substring(3,5).toUpperCase();
305                 }
306             	break;
307     		case 'nodejs':
308                 // running under nodejs
309                 var lang = process.env.LANG || process.env.LC_ALL;
310                 // the LANG variable on unix is in the form "lang_REGION.CHARSET"
311                 // where language and region are the correct ISO codes separated by
312                 // an underscore. This translate it back to the BCP-47 form.
313                 if (lang && typeof(lang) !== 'undefined') {
314                     ilib.locale = lang.substring(0,2).toLowerCase() + '-' + lang.substring(3,5).toUpperCase();
315                 }
316     			break;
317     		case 'qt':
318             	// running in the Javascript engine under Qt/QML
319             	var locobj = Qt.locale();
320             	var lang = locobj.name && locobj.name.replace("_", "-") || "en-US";
321     			break;
322     	}
323         ilib.locale = typeof(ilib.locale) === 'string' ? ilib.locale : 'en-US';
324     }
325     return ilib.locale;
326 };
327 
328 /**
329  * Sets the default time zone for all of ilib. This time zone will be used when
330  * no explicit time zone is passed to any ilib class. If the default time zone
331  * is not set, ilib will attempt to use the time zone of the
332  * environment it is running in, if it can find that. If not, it will
333  * default to the the UTC zone "Etc/UTC".<p>
334  * 
335  * 
336  * @static
337  * @param {string} tz the name of the time zone to set as the default time zone
338  */
339 ilib.setTimeZone = function (tz) {
340     ilib.tz = tz || ilib.tz;
341 };
342 
343 /**
344  * Return the default time zone for all of ilib if one has been set. This 
345  * time zone will be used when no explicit time zone is passed to any ilib 
346  * class. If the default time zone
347  * is not set, ilib will attempt to use the locale of the
348  * environment it is running in, if it can find that. If not, it will
349  * default to the the zone "local".<p>
350  * 
351  * 
352  * @static
353  * @return {string} the default time zone for ilib
354  */
355 ilib.getTimeZone = function() {
356     if (typeof(ilib.tz) === 'undefined') {
357         if (typeof(navigator) !== 'undefined' && typeof(navigator.timezone) !== 'undefined') {
358             // running in a browser
359             if (navigator.timezone.length > 0) {
360                 ilib.tz = navigator.timezone;
361             }
362         } else if (typeof(PalmSystem) !== 'undefined' && typeof(PalmSystem.timezone) !== 'undefined') {
363             // running in webkit on webOS
364             if (PalmSystem.timezone.length > 0) {
365                 ilib.tz = PalmSystem.timezone;
366             }
367         } else if (typeof(environment) !== 'undefined' && typeof(environment.user) !== 'undefined') {
368             // running under rhino
369             if (typeof(environment.user.timezone) !== 'undefined' && environment.user.timezone.length > 0) {
370                 ilib.tz = environment.user.timezone;
371             }
372         } else if (typeof(process) !== 'undefined' && typeof(process.env) !== 'undefined') {
373             // running in nodejs
374             if (process.env.TZ && typeof(process.env.TZ) !== "undefined") {
375                 ilib.tz = process.env.TZ;
376             }
377         }
378         
379         ilib.tz = ilib.tz || "local"; 
380     }
381 
382     return ilib.tz;
383 };
384 
385 /**
386  * @class
387  * Defines the interface for the loader class for ilib. The main method of the
388  * loader object is loadFiles(), which loads a set of requested locale data files
389  * from where-ever it is stored.
390  * @interface
391  */
392 ilib.Loader = function() {};
393 
394 /**
395  * Load a set of files from where-ever it is stored.<p>
396  * 
397  * This is the main function define a callback function for loading missing locale 
398  * data or resources.
399  * If this copy of ilib is assembled without including the required locale data
400  * or resources, then that data can be lazy loaded dynamically when it is 
401  * needed by calling this method. Each ilib class will first
402  * check for the existence of data under ilib.data, and if it is not there, 
403  * it will attempt to load it by calling this method of the laoder, and then place
404  * it there.<p>
405  * 
406  * Suggested implementations of this method might load files 
407  * directly from disk under nodejs or rhino, or within web pages, to load 
408  * files from the server with XHR calls.<p>
409  * 
410  * The first parameter to this method, paths, is an array of relative paths within 
411  * the ilib dir structure for the 
412  * requested data. These paths will already have the locale spec integrated 
413  * into them, so no further tweaking needs to happen to load the data. Simply
414  * load the named files. The second
415  * parameter tells the loader whether to load the files synchronously or asynchronously.
416  * If the sync parameters is false, then the onLoad function must also be specified.
417  * The third parameter gives extra parameters to the loader passed from the calling
418  * code. This may contain any property/value pairs.  The last parameter, callback,
419  * is a callback function to call when all of the data is finishing loading. Make
420  * sure to call the callback with the context of "this" so that the caller has their 
421  * context back again.<p>
422  * 
423  * The loader function must be able to operate either synchronously or asychronously. 
424  * If the loader function is called with an undefined callback function, it is
425  * expected to load the data synchronously, convert it to javascript
426  * objects, and return the array of json objects as the return value of the 
427  * function. If the loader 
428  * function is called with a callback function, it may load the data 
429  * synchronously or asynchronously (doesn't matter which) as long as it calls
430  * the callback function with the data converted to a javascript objects
431  * when it becomes available. If a particular file could not be loaded, the 
432  * loader function should put undefined into the corresponding entry in the
433  * results array. 
434  * Note that it is important that all the data is loaded before the callback
435  * is called.<p>
436  * 
437  * An example implementation for nodejs might be:
438  * 
439  * <pre>
440  *  * 
441  * var myLoader = function() {};
442  * myLoader.prototype = new Loader();
443  * myLoader.prototype.constructor = myLoader;
444  * myLoader.prototype.loadFiles = function(paths, sync, params, callback) {
445  *    if (sync) {
446  *        var ret = [];
447  *        // synchronous load -- just return the result
448  *        paths.forEach(function (path) {
449  *            var json = fs.readFileSync(path, "utf-8");
450  *            ret.push(json ? JSON.parse(json) : undefined);
451  *        });
452  *        
453  *        return ret;
454  *    }
455  *    this.callback = callback;
456  *
457  *    // asynchronous
458  *    this.results = [];
459  *    this._loadFilesAsync(paths);
460  * }
461  * myLoader.prototype._loadFilesAsync = function (paths) {
462  *    if (paths.length > 0) {
463  *        var file = paths.shift();
464  *        fs.readFile(file, "utf-8", function(err, json) {
465  *            this.results.push(err ? undefined : JSON.parse(json));
466  *            // call self recursively so that the callback is only called at the end
467  *            // when all the files are loaded sequentially
468  *            if (paths.length > 0) {
469  *                this._loadFilesAsync(paths);
470  *            } else {
471  *                this.callback(this.results);
472  *            }
473  *        });
474  *     }
475  * }
476  * 
477  * // bind to "this" so that "this" is relative to your own instance
478  * ilib.setLoaderCallback(new myLoader());
479  * </pre>
480 
481  * @param {Array.<string>} paths An array of paths to load from wherever the files are stored 
482  * @param {Boolean} sync if true, load the files synchronously, and false means asynchronously
483  * @param {Object} params an object with any extra parameters for the loader. These can be 
484  * anything. The caller of the ilib class passes these parameters in. Presumably, the code that
485  * calls ilib and the code that provides the loader are together and can have a private 
486  * agreement between them about what the parameters should contain.
487  * @param {function(Object)} callback function to call when the files are all loaded. The 
488  * parameter of the callback function is the contents of the files.
489  */
490 ilib.Loader.prototype.loadFiles = function (paths, sync, params, callback) {};
491 
492 /**
493  * Return all files available for loading using this loader instance.
494  * This method returns an object where the properties are the paths to
495  * directories where files are loaded from and the values are an array
496  * of strings containing the relative paths under the directory of each
497  * file that can be loaded.<p>
498  * 
499  * Example:
500  *  <pre>
501  *  {
502  *      "/usr/share/javascript/ilib/locale": [
503  *          "dateformats.json",
504  *          "aa/dateformats.json",
505  *          "af/dateformats.json",
506  *          "agq/dateformats.json",
507  *          "ak/dateformats.json",
508  *          ...
509  *          "zxx/dateformats.json"
510  *      ]
511  *  }
512  *  </pre>
513  * @returns {Object} a hash containing directory names and
514  * paths to file that can be loaded by this loader 
515  */
516 ilib.Loader.prototype.listAvailableFiles = function() {};
517 
518 /**
519  * Return true if the file in the named path is available for loading using
520  * this loader. The path may be given as an absolute path, in which case
521  * only that file is checked, or as a relative path, in which case, the
522  * relative path may appear underneath any of the directories that the loader
523  * knows about.
524  * @returns {boolean} true if the file in the named path is available for loading, and
525  * false otherwise
526  */
527 ilib.Loader.prototype.isAvailable = function(path) {};
528 
529 /**
530  * Set the custom loader used to load ilib's locale data in your environment. 
531  * The instance passed in must implement the Loader interface. See the
532  * Loader class documentation for more information about loaders. 
533  * 
534  * @static
535  * @param {ilib.Loader} loader class to call to access the requested data.
536  * @return {boolean} true if the loader was installed correctly, or false
537  * if not
538  */
539 ilib.setLoaderCallback = function(loader) {
540     // only a basic check
541     if ((typeof(loader) === 'object' && typeof(loader.loadFiles) === 'function') || 
542             typeof(loader) === 'function' || typeof(loader) === 'undefined') {
543         //console.log("setting callback loader to " + (loader ? loader.name : "undefined"));
544         ilib._load = loader;
545         return true;
546     }
547     return false;
548 };
549 
550 /**
551  * Return the custom Loader instance currently in use with this instance 
552  * of ilib. If there is no loader, this method returns undefined.
553  * 
554  * @protected
555  * @static
556  * @return {ilib.Loader|undefined} the loader instance currently in use, or 
557  * undefined if there is no such loader
558  */
559 ilib.getLoader = function() {
560 	return ilib._load;
561 };
562 
563 /**
564  * Test whether an object is an javascript array. 
565  * 
566  * @static
567  * @param {*} object The object to test
568  * @return {boolean} return true if the object is an array
569  * and false otherwise
570  */
571 ilib.isArray = function(object) {
572 	if (typeof(object) === 'object') {
573 		return Object.prototype.toString.call(object) === '[object Array]';
574 	}
575 	return false; 
576 };
577 
578 /**
579  * Extend object1 by mixing in everything from object2 into it. The objects
580  * are deeply extended, meaning that this method recursively descends the
581  * tree in the objects and mixes them in at each level. Arrays are extended
582  * by concatenating the elements of object2 onto those of object1.  
583  * 
584  * @static
585  * @param {Object} object1 the target object to extend
586  * @param {Object=} object2 the object to mix in to object1
587  * @return {Object} returns object1
588  */
589 ilib.extend = function (object1, object2) {
590 	var prop = undefined;
591 	if (object2) {
592 		for (prop in object2) {
593 			// don't extend object with undefined or functions
594 			if (prop && typeof(object2[prop]) !== 'undefined' && typeof(object2[prop]) !== "function") {
595 				if (ilib.isArray(object1[prop]) && ilib.isArray(object2[prop])) {
596 					//console.log("Merging array prop " + prop);
597 					object1[prop] = object1[prop].concat(object2[prop]);
598 				} else if (typeof(object1[prop]) === 'object' && typeof(object2[prop]) === 'object') {
599 					//console.log("Merging object prop " + prop);
600 					if (prop !== "ilib") {
601 						object1[prop] = ilib.extend(object1[prop], object2[prop]);
602 					}
603 				} else {
604 					//console.log("Copying prop " + prop);
605 					// for debugging. Used to determine whether or not json files are overriding their parents unnecessarily
606 					object1[prop] = object2[prop];
607 				}
608 			}
609 		}
610 	}
611 	return object1;
612 };
613 
614 ilib.extend2 = function (object1, object2) {
615 	var prop = undefined;
616 	if (object2) {
617 		for (prop in object2) {
618 			// don't extend object with undefined or functions
619 			if (prop && typeof(object2[prop]) !== 'undefined') {
620 				if (ilib.isArray(object1[prop]) && ilib.isArray(object2[prop])) {
621 					//console.log("Merging array prop " + prop);
622 					object1[prop] = object1[prop].concat(object2[prop]);
623 				} else if (typeof(object1[prop]) === 'object' && typeof(object2[prop]) === 'object') {
624 					//console.log("Merging object prop " + prop);
625 					if (prop !== "ilib") {
626 						object1[prop] = ilib.extend2(object1[prop], object2[prop]);
627 					}
628 				} else {
629 					//console.log("Copying prop " + prop);
630 					// for debugging. Used to determine whether or not json files are overriding their parents unnecessarily
631 					object1[prop] = object2[prop];
632 				}
633 			}
634 		}
635 	}
636 	return object1;
637 };
638 
639 /**
640  * If Function.prototype.bind does not exist in this JS engine, this
641  * function reimplements it in terms of older JS functions.
642  * bind() doesn't exist in many older browsers.
643  * 
644  * @static
645  * @param {Object} scope object that the method should operate on
646  * @param {function(...)} method method to call
647  * @return {function(...)|undefined} function that calls the given method 
648  * in the given scope with all of its arguments properly attached, or
649  * undefined if there was a problem with the arguments
650  */
651 ilib.bind = function(scope, method/*, bound arguments*/){
652 	if (!scope || !method) {
653 		return undefined;
654 	}
655 	
656 	/** @protected 
657 	 * @param {Arguments} inArrayLike
658 	 * @param {number=} inOffset
659 	 */
660 	function cloneArray(inArrayLike, inOffset) {
661 		var arr = [];
662 		for(var i = inOffset || 0, l = inArrayLike.length; i<l; i++){
663 			arr.push(inArrayLike[i]);
664 		}
665 		return arr;
666 	}
667 
668 	if (typeof(method) === 'function') {
669 		var func, args = cloneArray(arguments, 2);
670 		if (typeof(method.bind) === 'function') {
671 			func = method.bind.apply(method, [scope].concat(args));
672 		} else {
673 			func = function() {
674 				var nargs = cloneArray(arguments);
675 				// invoke with collected args
676 				return method.apply(scope, args.concat(nargs));
677 			};
678 		}
679 		return func;
680 	}
681 	return undefined;
682 };
683 
684 /**
685  * @private
686  */
687 ilib._dyncode = false;
688 
689 /**
690  * Return true if this copy of ilib is using dynamically loaded code. It returns
691  * false for pre-assembled code.
692  * 
693  * @static
694  * @return {boolean} true if this ilib uses dynamically loaded code, and false otherwise
695  */
696 ilib.isDynCode = function() {
697 	return ilib._dyncode;
698 };
699 
700 /**
701  * @private
702  */
703 ilib._dyndata = false;
704 
705 /**
706  * Return true if this copy of ilib is using dynamically loaded locale data. It returns
707  * false for pre-assembled data.
708  * 
709  * @static
710  * @return {boolean} true if this ilib uses dynamically loaded locale data, and false otherwise
711  */
712 ilib.isDynData = function() {
713 	return ilib._dyndata;
714 };
715 
716 ilib._loadtime = new Date().getTime();
717 /*< JSUtils.js */
718 /*
719  * JSUtils.js - Misc utilities to work around Javascript engine differences
720  * 
721  * Copyright © 2013-2015, JEDLSoft
722  *
723  * Licensed under the Apache License, Version 2.0 (the "License");
724  * you may not use this file except in compliance with the License.
725  * You may obtain a copy of the License at
726  *
727  *     http://www.apache.org/licenses/LICENSE-2.0
728  *
729  * Unless required by applicable law or agreed to in writing, software
730  * distributed under the License is distributed on an "AS IS" BASIS,
731  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
732  *
733  * See the License for the specific language governing permissions and
734  * limitations under the License.
735  */
736 
737 // !depends ilib.js
738 
739 
740 var JSUtils = {};
741 
742 /**
743  * Perform a shallow copy of the source object to the target object. This only 
744  * copies the assignments of the source properties to the target properties, 
745  * but not recursively from there.<p>
746  * 
747  * 
748  * @static
749  * @param {Object} source the source object to copy properties from
750  * @param {Object} target the target object to copy properties into
751  */
752 JSUtils.shallowCopy = function (source, target) {
753 	var prop = undefined;
754 	if (source && target) {
755 		for (prop in source) {
756 			if (prop !== undefined && typeof(source[prop]) !== 'undefined') {
757 				target[prop] = source[prop];
758 			}
759 		}
760 	}
761 };
762 
763 /**
764  * Perform a recursive deep copy from the "from" object to the "deep" object.
765  * 
766  * @static
767  * @param {Object} from the object to copy from
768  * @param {Object} to the object to copy to
769  * @return {Object} a reference to the the "to" object
770  */
771 JSUtils.deepCopy = function(from, to) {
772 	var prop;
773 
774 	for (prop in from) {
775 		if (prop) {
776 			if (typeof(from[prop]) === 'object') {
777 				to[prop] = {};
778 				JSUtils.deepCopy(from[prop], to[prop]);
779 			} else {
780 				to[prop] = from[prop];
781 			}
782 		}
783 	}
784 	return to;
785 };
786 
787 /**
788  * Map a string to the given set of alternate characters. If the target set
789  * does not contain a particular character in the input string, then that
790  * character will be copied to the output unmapped.
791  * 
792  * @static
793  * @param {string} str a string to map to an alternate set of characters
794  * @param {Array.<string>|Object} map a mapping to alternate characters
795  * @return {string} the source string where each character is mapped to alternate characters
796  */
797 JSUtils.mapString = function (str, map) {
798 	var mapped = "";
799 	if (map && str) {
800 		for (var i = 0; i < str.length; i++) {
801 			var c = str.charAt(i); // TODO use a char iterator?
802 			mapped += map[c] || c; 
803 		}
804 	} else {
805 		mapped = str;
806 	}
807 	return mapped;
808 };
809 
810 /**
811  * Check if an object is a member of the given array. If this javascript engine
812  * support indexOf, it is used directly. Otherwise, this function implements it
813  * itself. The idea is to make sure that you can use the quick indexOf if it is
814  * available, but use a slower implementation in older engines as well.
815  * 
816  * @static
817  * @param {Array.<Object>} array array to search
818  * @param {Object} obj object being sought. This should be of the same type as the
819  * members of the array being searched. If not, this function will not return
820  * any results.
821  * @return {number} index of the object in the array, or -1 if it is not in the array.
822  */
823 JSUtils.indexOf = function(array, obj) {
824 	if (!array || !obj) {
825 		return -1;
826 	}
827 	if (typeof(array.indexOf) === 'function') {
828 		return array.indexOf(obj);
829 	} else {
830 		for (var i = 0; i < array.length; i++) {
831 	        if (array[i] === obj) {
832 	            return i;
833 	        }
834 	    }
835 	    return -1;
836 	}
837 };
838 
839 /**
840  * Pad the str with zeros to the given length of digits.
841  * 
842  * @static
843  * @param {string|number} str the string or number to pad
844  * @param {number} length the desired total length of the output string, padded
845  * @param {boolean=} right if true, pad on the right side of the number rather than the left.
846  * Default is false.
847  */
848 JSUtils.pad = function (str, length, right) {
849 	if (typeof(str) !== 'string') {
850 		str = "" + str;
851 	}
852 	var start = 0;
853 	// take care of negative numbers
854 	if (str.charAt(0) === '-') {
855 		start++;
856 	}
857 	return (str.length >= length+start) ? str : 
858 		(right ? str + JSUtils.pad.zeros.substring(0,length-str.length+start) : 
859 			str.substring(0, start) + JSUtils.pad.zeros.substring(0,length-str.length+start) + str.substring(start));
860 };
861 
862 /** @private */
863 JSUtils.pad.zeros = "00000000000000000000000000000000";
864 
865 /**
866  * Convert a string into the hexadecimal representation
867  * of the Unicode characters in that string.
868  * 
869  * @static
870  * @param {string} string The string to convert
871  * @param {number=} limit the number of digits to use to represent the character (1 to 8)
872  * @return {string} a hexadecimal representation of the
873  * Unicode characters in the input string
874  */
875 JSUtils.toHexString = function(string, limit) {
876 	var i, 
877 		result = "", 
878 		lim = (limit && limit < 9) ? limit : 4;
879 	
880 	if (!string) {
881 		return "";
882 	}
883 	for (i = 0; i < string.length; i++) {
884 		var ch = string.charCodeAt(i).toString(16);
885 		result += JSUtils.pad(ch, lim);
886 	}
887 	return result.toUpperCase();
888 };
889 
890 /**
891  * Test whether an object in a Javascript Date. 
892  * 
893  * @static
894  * @param {Object|null|undefined} object The object to test
895  * @return {boolean} return true if the object is a Date
896  * and false otherwise
897  */
898 JSUtils.isDate = function(object) {
899 	if (typeof(object) === 'object') {
900 		return Object.prototype.toString.call(object) === '[object Date]';
901 	}
902 	return false; 
903 };
904 
905 /**
906  * Merge the properties of object2 into object1 in a deep manner and return a merged
907  * object. If the property exists in both objects, the value in object2 will overwrite 
908  * the value in object1. If a property exists in object1, but not in object2, its value
909  * will not be touched. If a property exists in object2, but not in object1, it will be 
910  * added to the merged result.<p>
911  * 
912  * Name1 and name2 are for creating debug output only. They are not necessary.<p>
913  * 
914  * 
915  * @static
916  * @param {*} object1 the object to merge into
917  * @param {*} object2 the object to merge
918  * @param {boolean=} replace if true, replace the array elements in object1 with those in object2.
919  * If false, concatenate array elements in object1 with items in object2.
920  * @param {string=} name1 name of the object being merged into
921  * @param {string=} name2 name of the object being merged in
922  * @return {Object} the merged object
923  */
924 JSUtils.merge = function (object1, object2, replace, name1, name2) {
925 	var prop = undefined,
926 		newObj = {};
927 	for (prop in object1) {
928 		if (prop && typeof(object1[prop]) !== 'undefined') {
929 			newObj[prop] = object1[prop];
930 		}
931 	}
932 	for (prop in object2) {
933 		if (prop && typeof(object2[prop]) !== 'undefined') {
934 			if (ilib.isArray(object1[prop]) && ilib.isArray(object2[prop])) {
935 				if (typeof(replace) !== 'boolean' || !replace) {
936 					newObj[prop] = [].concat(object1[prop]);
937 					newObj[prop] = newObj[prop].concat(object2[prop]);
938 				} else {
939 					newObj[prop] = object2[prop];
940 				}
941 			} else if (typeof(object1[prop]) === 'object' && typeof(object2[prop]) === 'object') {
942 				newObj[prop] = JSUtils.merge(object1[prop], object2[prop], replace);
943 			} else {
944 				// for debugging. Used to determine whether or not json files are overriding their parents unnecessarily
945 				if (name1 && name2 && newObj[prop] == object2[prop]) {
946 					console.log("Property " + prop + " in " + name1 + " is being overridden by the same value in " + name2);
947 				}
948 				newObj[prop] = object2[prop];
949 			}
950 		}
951 	}
952 	return newObj;
953 };
954 
955 /**
956  * Return true if the given object has no properties.<p>
957  * 
958  * 
959  * @static
960  * @param {Object} obj the object to check
961  * @return {boolean} true if the given object has no properties, false otherwise
962  */
963 JSUtils.isEmpty = function (obj) {
964 	var prop = undefined;
965 	
966 	if (!obj) {
967 		return true;
968 	}
969 	
970 	for (prop in obj) {
971 		if (prop && typeof(obj[prop]) !== 'undefined') {
972 			return false;
973 		}
974 	}
975 	return true;
976 };
977 
978 /**
979  * @static
980  */
981 JSUtils.hashCode = function(obj) {
982 	var hash = 0;
983 	
984 	function addHash(hash, newValue) {
985 		// co-prime numbers creates a nicely distributed hash
986 		hash *= 65543;
987 		hash += newValue;
988 		hash %= 2147483647; 
989 		return hash;
990 	}
991 	
992 	function stringHash(str) {
993 		var hash = 0;
994 		for (var i = 0; i < str.length; i++) {
995 			hash = addHash(hash, str.charCodeAt(i));
996 		}
997 		return hash;
998 	}
999 	
1000 	switch (typeof(obj)) {
1001 		case 'undefined':
1002 			hash = 0;
1003 			break;
1004 		case 'string':
1005 			hash = stringHash(obj);
1006 			break;
1007 		case 'function':
1008 		case 'number':
1009 		case 'xml':
1010 			hash = stringHash(String(obj));
1011 			break;
1012 		case 'boolean':
1013 			hash = obj ? 1 : 0;
1014 			break;
1015 		case 'object':
1016 			var props = [];
1017 			for (var p in obj) {
1018 				if (obj.hasOwnProperty(p)) {
1019 					props.push(p);
1020 				}
1021 			}
1022 			// make sure the order of the properties doesn't matter
1023 			props.sort();
1024 			for (var i = 0; i < props.length; i++) {
1025 				hash = addHash(hash, stringHash(props[i]));
1026 				hash = addHash(hash, JSUtils.hashCode(obj[props[i]]));
1027 			}
1028 			break;
1029 	}
1030 	
1031 	return hash;
1032 };
1033 
1034 
1035 
1036 
1037 /*< Locale.js */
1038 /*
1039  * Locale.js - Locale specifier definition
1040  * 
1041  * Copyright © 2012-2015, JEDLSoft
1042  *
1043  * Licensed under the Apache License, Version 2.0 (the "License");
1044  * you may not use this file except in compliance with the License.
1045  * You may obtain a copy of the License at
1046  *
1047  *     http://www.apache.org/licenses/LICENSE-2.0
1048  *
1049  * Unless required by applicable law or agreed to in writing, software
1050  * distributed under the License is distributed on an "AS IS" BASIS,
1051  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1052  *
1053  * See the License for the specific language governing permissions and
1054  * limitations under the License.
1055  */
1056 
1057 // !depends ilib.js JSUtils.js
1058 
1059 
1060 /**
1061  * @class
1062  * Create a new locale instance. Locales are specified either with a specifier string 
1063  * that follows the BCP-47 convention (roughly: "language-region-script-variant") or 
1064  * with 4 parameters that specify the language, region, variant, and script individually.<p>
1065  * 
1066  * The language is given as an ISO 639-1 two-letter, lower-case language code. You
1067  * can find a full list of these codes at 
1068  * <a href="http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes">http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes</a><p>
1069  * 
1070  * The region is given as an ISO 3166-1 two-letter, upper-case region code. You can
1071  * find a full list of these codes at 
1072  * <a href="http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2">http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2</a>.<p>
1073  * 
1074  * The variant is any string that does not contain a dash which further differentiates
1075  * locales from each other.<p>
1076  * 
1077  * The script is given as the ISO 15924 four-letter script code. In some locales,
1078  * text may be validly written in more than one script. For example, Serbian is often
1079  * written in both Latin and Cyrillic, though not usually mixed together. You can find a
1080  * full list of these codes at 
1081  * <a href="http://en.wikipedia.org/wiki/ISO_15924#List_of_codes">http://en.wikipedia.org/wiki/ISO_15924#List_of_codes</a>.<p>
1082  * 
1083  * As an example in ilib, the script can be used in the date formatter. Dates formatted 
1084  * in Serbian could have day-of-week names or month names written in the Latin
1085  * or Cyrillic script. Often one script is default such that sr-SR-Latn is the same
1086  * as sr-SR so the script code "Latn" can be left off of the locale spec.<p> 
1087  * 
1088  * Each part is optional, and an empty string in the specifier before or after a 
1089  * dash or as a parameter to the constructor denotes an unspecified value. In this
1090  * case, many of the ilib functions will treat the locale as generic. For example
1091  * the locale "en-" is equivalent to "en" and to "en--" and denotes a locale
1092  * of "English" with an unspecified region and variant, which typically matches
1093  * any region or variant.<p>
1094  * 
1095  * Without any arguments to the constructor, this function returns the locale of
1096  * the host Javascript engine.<p>
1097  * 
1098  * 
1099  * @constructor
1100  * @param {?string|Locale=} language the ISO 639 2-letter code for the language, or a full 
1101  * locale spec in BCP-47 format, or another Locale instance to copy from
1102  * @param {string=} region the ISO 3166 2-letter code for the region
1103  * @param {string=} variant the name of the variant of this locale, if any
1104  * @param {string=} script the ISO 15924 code of the script for this locale, if any
1105  */
1106 var Locale = function(language, region, variant, script) {
1107 	if (typeof(region) === 'undefined') {
1108 		var spec = language || ilib.getLocale();
1109 		if (typeof(spec) === 'string') {
1110 			var parts = spec.split('-');
1111 	        for ( var i = 0; i < parts.length; i++ ) {
1112 	        	if (Locale._isLanguageCode(parts[i])) {
1113 	    			/** 
1114 	    			 * @private
1115 	    			 * @type {string|undefined}
1116 	    			 */
1117 	        		this.language = parts[i];
1118 	        	} else if (Locale._isRegionCode(parts[i])) {
1119 	    			/** 
1120 	    			 * @private
1121 	    			 * @type {string|undefined}
1122 	    			 */
1123 	        		this.region = parts[i];
1124 	        	} else if (Locale._isScriptCode(parts[i])) {
1125 	    			/** 
1126 	    			 * @private
1127 	    			 * @type {string|undefined}
1128 	    			 */
1129 	        		this.script = parts[i];
1130 	        	} else {
1131 	    			/** 
1132 	    			 * @private
1133 	    			 * @type {string|undefined}
1134 	    			 */
1135 	        		this.variant = parts[i];
1136 	        	}
1137 	        }
1138 	        this.language = this.language || undefined;
1139 	        this.region = this.region || undefined;
1140 	        this.script = this.script || undefined;
1141 	        this.variant = this.variant || undefined;
1142 		} else if (typeof(spec) === 'object') {
1143 	        this.language = spec.language || undefined;
1144 	        this.region = spec.region || undefined;
1145 	        this.script = spec.script || undefined;
1146 	        this.variant = spec.variant || undefined;
1147 		}
1148 	} else {
1149 		if (language) {
1150 			language = language.trim();
1151 			this.language = language.length > 0 ? language.toLowerCase() : undefined;
1152 		} else {
1153 			this.language = undefined;
1154 		}
1155 		if (region) {
1156 			region = region.trim();
1157 			this.region = region.length > 0 ? region.toUpperCase() : undefined;
1158 		} else {
1159 			this.region = undefined;
1160 		}
1161 		if (variant) {
1162 			variant = variant.trim();
1163 			this.variant = variant.length > 0 ? variant : undefined;
1164 		} else {
1165 			this.variant = undefined;
1166 		}
1167 		if (script) {
1168 			script = script.trim();
1169 			this.script = script.length > 0 ? script : undefined;
1170 		} else {
1171 			this.script = undefined;
1172 		}
1173 	}
1174 	this._genSpec();
1175 };
1176 
1177 // from http://en.wikipedia.org/wiki/ISO_3166-1
1178 Locale.a2toa3regmap = {
1179 	"AF": "AFG",
1180 	"AX": "ALA",
1181 	"AL": "ALB",
1182 	"DZ": "DZA",
1183 	"AS": "ASM",
1184 	"AD": "AND",
1185 	"AO": "AGO",
1186 	"AI": "AIA",
1187 	"AQ": "ATA",
1188 	"AG": "ATG",
1189 	"AR": "ARG",
1190 	"AM": "ARM",
1191 	"AW": "ABW",
1192 	"AU": "AUS",
1193 	"AT": "AUT",
1194 	"AZ": "AZE",
1195 	"BS": "BHS",
1196 	"BH": "BHR",
1197 	"BD": "BGD",
1198 	"BB": "BRB",
1199 	"BY": "BLR",
1200 	"BE": "BEL",
1201 	"BZ": "BLZ",
1202 	"BJ": "BEN",
1203 	"BM": "BMU",
1204 	"BT": "BTN",
1205 	"BO": "BOL",
1206 	"BQ": "BES",
1207 	"BA": "BIH",
1208 	"BW": "BWA",
1209 	"BV": "BVT",
1210 	"BR": "BRA",
1211 	"IO": "IOT",
1212 	"BN": "BRN",
1213 	"BG": "BGR",
1214 	"BF": "BFA",
1215 	"BI": "BDI",
1216 	"KH": "KHM",
1217 	"CM": "CMR",
1218 	"CA": "CAN",
1219 	"CV": "CPV",
1220 	"KY": "CYM",
1221 	"CF": "CAF",
1222 	"TD": "TCD",
1223 	"CL": "CHL",
1224 	"CN": "CHN",
1225 	"CX": "CXR",
1226 	"CC": "CCK",
1227 	"CO": "COL",
1228 	"KM": "COM",
1229 	"CG": "COG",
1230 	"CD": "COD",
1231 	"CK": "COK",
1232 	"CR": "CRI",
1233 	"CI": "CIV",
1234 	"HR": "HRV",
1235 	"CU": "CUB",
1236 	"CW": "CUW",
1237 	"CY": "CYP",
1238 	"CZ": "CZE",
1239 	"DK": "DNK",
1240 	"DJ": "DJI",
1241 	"DM": "DMA",
1242 	"DO": "DOM",
1243 	"EC": "ECU",
1244 	"EG": "EGY",
1245 	"SV": "SLV",
1246 	"GQ": "GNQ",
1247 	"ER": "ERI",
1248 	"EE": "EST",
1249 	"ET": "ETH",
1250 	"FK": "FLK",
1251 	"FO": "FRO",
1252 	"FJ": "FJI",
1253 	"FI": "FIN",
1254 	"FR": "FRA",
1255 	"GF": "GUF",
1256 	"PF": "PYF",
1257 	"TF": "ATF",
1258 	"GA": "GAB",
1259 	"GM": "GMB",
1260 	"GE": "GEO",
1261 	"DE": "DEU",
1262 	"GH": "GHA",
1263 	"GI": "GIB",
1264 	"GR": "GRC",
1265 	"GL": "GRL",
1266 	"GD": "GRD",
1267 	"GP": "GLP",
1268 	"GU": "GUM",
1269 	"GT": "GTM",
1270 	"GG": "GGY",
1271 	"GN": "GIN",
1272 	"GW": "GNB",
1273 	"GY": "GUY",
1274 	"HT": "HTI",
1275 	"HM": "HMD",
1276 	"VA": "VAT",
1277 	"HN": "HND",
1278 	"HK": "HKG",
1279 	"HU": "HUN",
1280 	"IS": "ISL",
1281 	"IN": "IND",
1282 	"ID": "IDN",
1283 	"IR": "IRN",
1284 	"IQ": "IRQ",
1285 	"IE": "IRL",
1286 	"IM": "IMN",
1287 	"IL": "ISR",
1288 	"IT": "ITA",
1289 	"JM": "JAM",
1290 	"JP": "JPN",
1291 	"JE": "JEY",
1292 	"JO": "JOR",
1293 	"KZ": "KAZ",
1294 	"KE": "KEN",
1295 	"KI": "KIR",
1296 	"KP": "PRK",
1297 	"KR": "KOR",
1298 	"KW": "KWT",
1299 	"KG": "KGZ",
1300 	"LA": "LAO",
1301 	"LV": "LVA",
1302 	"LB": "LBN",
1303 	"LS": "LSO",
1304 	"LR": "LBR",
1305 	"LY": "LBY",
1306 	"LI": "LIE",
1307 	"LT": "LTU",
1308 	"LU": "LUX",
1309 	"MO": "MAC",
1310 	"MK": "MKD",
1311 	"MG": "MDG",
1312 	"MW": "MWI",
1313 	"MY": "MYS",
1314 	"MV": "MDV",
1315 	"ML": "MLI",
1316 	"MT": "MLT",
1317 	"MH": "MHL",
1318 	"MQ": "MTQ",
1319 	"MR": "MRT",
1320 	"MU": "MUS",
1321 	"YT": "MYT",
1322 	"MX": "MEX",
1323 	"FM": "FSM",
1324 	"MD": "MDA",
1325 	"MC": "MCO",
1326 	"MN": "MNG",
1327 	"ME": "MNE",
1328 	"MS": "MSR",
1329 	"MA": "MAR",
1330 	"MZ": "MOZ",
1331 	"MM": "MMR",
1332 	"NA": "NAM",
1333 	"NR": "NRU",
1334 	"NP": "NPL",
1335 	"NL": "NLD",
1336 	"NC": "NCL",
1337 	"NZ": "NZL",
1338 	"NI": "NIC",
1339 	"NE": "NER",
1340 	"NG": "NGA",
1341 	"NU": "NIU",
1342 	"NF": "NFK",
1343 	"MP": "MNP",
1344 	"NO": "NOR",
1345 	"OM": "OMN",
1346 	"PK": "PAK",
1347 	"PW": "PLW",
1348 	"PS": "PSE",
1349 	"PA": "PAN",
1350 	"PG": "PNG",
1351 	"PY": "PRY",
1352 	"PE": "PER",
1353 	"PH": "PHL",
1354 	"PN": "PCN",
1355 	"PL": "POL",
1356 	"PT": "PRT",
1357 	"PR": "PRI",
1358 	"QA": "QAT",
1359 	"RE": "REU",
1360 	"RO": "ROU",
1361 	"RU": "RUS",
1362 	"RW": "RWA",
1363 	"BL": "BLM",
1364 	"SH": "SHN",
1365 	"KN": "KNA",
1366 	"LC": "LCA",
1367 	"MF": "MAF",
1368 	"PM": "SPM",
1369 	"VC": "VCT",
1370 	"WS": "WSM",
1371 	"SM": "SMR",
1372 	"ST": "STP",
1373 	"SA": "SAU",
1374 	"SN": "SEN",
1375 	"RS": "SRB",
1376 	"SC": "SYC",
1377 	"SL": "SLE",
1378 	"SG": "SGP",
1379 	"SX": "SXM",
1380 	"SK": "SVK",
1381 	"SI": "SVN",
1382 	"SB": "SLB",
1383 	"SO": "SOM",
1384 	"ZA": "ZAF",
1385 	"GS": "SGS",
1386 	"SS": "SSD",
1387 	"ES": "ESP",
1388 	"LK": "LKA",
1389 	"SD": "SDN",
1390 	"SR": "SUR",
1391 	"SJ": "SJM",
1392 	"SZ": "SWZ",
1393 	"SE": "SWE",
1394 	"CH": "CHE",
1395 	"SY": "SYR",
1396 	"TW": "TWN",
1397 	"TJ": "TJK",
1398 	"TZ": "TZA",
1399 	"TH": "THA",
1400 	"TL": "TLS",
1401 	"TG": "TGO",
1402 	"TK": "TKL",
1403 	"TO": "TON",
1404 	"TT": "TTO",
1405 	"TN": "TUN",
1406 	"TR": "TUR",
1407 	"TM": "TKM",
1408 	"TC": "TCA",
1409 	"TV": "TUV",
1410 	"UG": "UGA",
1411 	"UA": "UKR",
1412 	"AE": "ARE",
1413 	"GB": "GBR",
1414 	"US": "USA",
1415 	"UM": "UMI",
1416 	"UY": "URY",
1417 	"UZ": "UZB",
1418 	"VU": "VUT",
1419 	"VE": "VEN",
1420 	"VN": "VNM",
1421 	"VG": "VGB",
1422 	"VI": "VIR",
1423 	"WF": "WLF",
1424 	"EH": "ESH",
1425 	"YE": "YEM",
1426 	"ZM": "ZMB",
1427 	"ZW": "ZWE"
1428 };
1429 
1430 
1431 Locale.a1toa3langmap = {
1432 	"ab": "abk",
1433 	"aa": "aar",
1434 	"af": "afr",
1435 	"ak": "aka",
1436 	"sq": "sqi",
1437 	"am": "amh",
1438 	"ar": "ara",
1439 	"an": "arg",
1440 	"hy": "hye",
1441 	"as": "asm",
1442 	"av": "ava",
1443 	"ae": "ave",
1444 	"ay": "aym",
1445 	"az": "aze",
1446 	"bm": "bam",
1447 	"ba": "bak",
1448 	"eu": "eus",
1449 	"be": "bel",
1450 	"bn": "ben",
1451 	"bh": "bih",
1452 	"bi": "bis",
1453 	"bs": "bos",
1454 	"br": "bre",
1455 	"bg": "bul",
1456 	"my": "mya",
1457 	"ca": "cat",
1458 	"ch": "cha",
1459 	"ce": "che",
1460 	"ny": "nya",
1461 	"zh": "zho",
1462 	"cv": "chv",
1463 	"kw": "cor",
1464 	"co": "cos",
1465 	"cr": "cre",
1466 	"hr": "hrv",
1467 	"cs": "ces",
1468 	"da": "dan",
1469 	"dv": "div",
1470 	"nl": "nld",
1471 	"dz": "dzo",
1472 	"en": "eng",
1473 	"eo": "epo",
1474 	"et": "est",
1475 	"ee": "ewe",
1476 	"fo": "fao",
1477 	"fj": "fij",
1478 	"fi": "fin",
1479 	"fr": "fra",
1480 	"ff": "ful",
1481 	"gl": "glg",
1482 	"ka": "kat",
1483 	"de": "deu",
1484 	"el": "ell",
1485 	"gn": "grn",
1486 	"gu": "guj",
1487 	"ht": "hat",
1488 	"ha": "hau",
1489 	"he": "heb",
1490 	"hz": "her",
1491 	"hi": "hin",
1492 	"ho": "hmo",
1493 	"hu": "hun",
1494 	"ia": "ina",
1495 	"id": "ind",
1496 	"ie": "ile",
1497 	"ga": "gle",
1498 	"ig": "ibo",
1499 	"ik": "ipk",
1500 	"io": "ido",
1501 	"is": "isl",
1502 	"it": "ita",
1503 	"iu": "iku",
1504 	"ja": "jpn",
1505 	"jv": "jav",
1506 	"kl": "kal",
1507 	"kn": "kan",
1508 	"kr": "kau",
1509 	"ks": "kas",
1510 	"kk": "kaz",
1511 	"km": "khm",
1512 	"ki": "kik",
1513 	"rw": "kin",
1514 	"ky": "kir",
1515 	"kv": "kom",
1516 	"kg": "kon",
1517 	"ko": "kor",
1518 	"ku": "kur",
1519 	"kj": "kua",
1520 	"la": "lat",
1521 	"lb": "ltz",
1522 	"lg": "lug",
1523 	"li": "lim",
1524 	"ln": "lin",
1525 	"lo": "lao",
1526 	"lt": "lit",
1527 	"lu": "lub",
1528 	"lv": "lav",
1529 	"gv": "glv",
1530 	"mk": "mkd",
1531 	"mg": "mlg",
1532 	"ms": "msa",
1533 	"ml": "mal",
1534 	"mt": "mlt",
1535 	"mi": "mri",
1536 	"mr": "mar",
1537 	"mh": "mah",
1538 	"mn": "mon",
1539 	"na": "nau",
1540 	"nv": "nav",
1541 	"nb": "nob",
1542 	"nd": "nde",
1543 	"ne": "nep",
1544 	"ng": "ndo",
1545 	"nn": "nno",
1546 	"no": "nor",
1547 	"ii": "iii",
1548 	"nr": "nbl",
1549 	"oc": "oci",
1550 	"oj": "oji",
1551 	"cu": "chu",
1552 	"om": "orm",
1553 	"or": "ori",
1554 	"os": "oss",
1555 	"pa": "pan",
1556 	"pi": "pli",
1557 	"fa": "fas",
1558 	"pl": "pol",
1559 	"ps": "pus",
1560 	"pt": "por",
1561 	"qu": "que",
1562 	"rm": "roh",
1563 	"rn": "run",
1564 	"ro": "ron",
1565 	"ru": "rus",
1566 	"sa": "san",
1567 	"sc": "srd",
1568 	"sd": "snd",
1569 	"se": "sme",
1570 	"sm": "smo",
1571 	"sg": "sag",
1572 	"sr": "srp",
1573 	"gd": "gla",
1574 	"sn": "sna",
1575 	"si": "sin",
1576 	"sk": "slk",
1577 	"sl": "slv",
1578 	"so": "som",
1579 	"st": "sot",
1580 	"es": "spa",
1581 	"su": "sun",
1582 	"sw": "swa",
1583 	"ss": "ssw",
1584 	"sv": "swe",
1585 	"ta": "tam",
1586 	"te": "tel",
1587 	"tg": "tgk",
1588 	"th": "tha",
1589 	"ti": "tir",
1590 	"bo": "bod",
1591 	"tk": "tuk",
1592 	"tl": "tgl",
1593 	"tn": "tsn",
1594 	"to": "ton",
1595 	"tr": "tur",
1596 	"ts": "tso",
1597 	"tt": "tat",
1598 	"tw": "twi",
1599 	"ty": "tah",
1600 	"ug": "uig",
1601 	"uk": "ukr",
1602 	"ur": "urd",
1603 	"uz": "uzb",
1604 	"ve": "ven",
1605 	"vi": "vie",
1606 	"vo": "vol",
1607 	"wa": "wln",
1608 	"cy": "cym",
1609 	"wo": "wol",
1610 	"fy": "fry",
1611 	"xh": "xho",
1612 	"yi": "yid",
1613 	"yo": "yor",
1614 	"za": "zha",
1615 	"zu": "zul"
1616 };
1617 
1618 /**
1619  * Tell whether or not the str does not start with a lower case ASCII char.
1620  * @private
1621  * @param {string} str the char to check
1622  * @return {boolean} true if the char is not a lower case ASCII char
1623  */
1624 Locale._notLower = function(str) {
1625 	// do this with ASCII only so we don't have to depend on the CType functions
1626 	var ch = str.charCodeAt(0);
1627 	return ch < 97 || ch > 122;
1628 };
1629 
1630 /**
1631  * Tell whether or not the str does not start with an upper case ASCII char.
1632  * @private
1633  * @param {string} str the char to check
1634  * @return {boolean} true if the char is a not an upper case ASCII char
1635  */
1636 Locale._notUpper = function(str) {
1637 	// do this with ASCII only so we don't have to depend on the CType functions
1638 	var ch = str.charCodeAt(0);
1639 	return ch < 65 || ch > 90;
1640 };
1641 
1642 /**
1643  * Tell whether or not the str does not start with a digit char.
1644  * @private
1645  * @param {string} str the char to check
1646  * @return {boolean} true if the char is a not an upper case ASCII char
1647  */
1648 Locale._notDigit = function(str) {
1649 	// do this with ASCII only so we don't have to depend on the CType functions
1650 	var ch = str.charCodeAt(0);
1651 	return ch < 48 || ch > 57;
1652 };
1653 
1654 /**
1655  * Tell whether or not the given string has the correct syntax to be 
1656  * an ISO 639 language code.
1657  * 
1658  * @private
1659  * @param {string} str the string to parse
1660  * @return {boolean} true if the string could syntactically be a language code.
1661  */
1662 Locale._isLanguageCode = function(str) {
1663 	if (typeof(str) === 'undefined' || str.length < 2 || str.length > 3) {
1664 		return false;
1665 	}
1666 
1667 	for (var i = 0; i < str.length; i++) {
1668 		if (Locale._notLower(str.charAt(i))) {
1669 			return false;
1670 		}
1671 	}
1672 	
1673 	return true;
1674 };
1675 
1676 /**
1677  * Tell whether or not the given string has the correct syntax to be 
1678  * an ISO 3166 2-letter region code or M.49 3-digit region code.
1679  * 
1680  * @private
1681  * @param {string} str the string to parse
1682  * @return {boolean} true if the string could syntactically be a language code.
1683  */
1684 Locale._isRegionCode = function (str) {
1685 	if (typeof(str) === 'undefined' || str.length < 2 || str.length > 3) {
1686 		return false;
1687 	}
1688 	
1689 	if (str.length === 2) {
1690 		for (var i = 0; i < str.length; i++) {
1691 			if (Locale._notUpper(str.charAt(i))) {
1692 				return false;
1693 			}
1694 		}
1695 	} else {
1696 		for (var i = 0; i < str.length; i++) {
1697 			if (Locale._notDigit(str.charAt(i))) {
1698 				return false;
1699 			}
1700 		}
1701 	}
1702 	
1703 	return true;
1704 };
1705 
1706 /**
1707  * Tell whether or not the given string has the correct syntax to be 
1708  * an ISO 639 language code.
1709  * 
1710  * @private
1711  * @param {string} str the string to parse
1712  * @return {boolean} true if the string could syntactically be a language code.
1713  */
1714 Locale._isScriptCode = function(str) {
1715 	if (typeof(str) === 'undefined' || str.length !== 4 || Locale._notUpper(str.charAt(0))) {
1716 		return false;
1717 	}
1718 	
1719 	for (var i = 1; i < 4; i++) {
1720 		if (Locale._notLower(str.charAt(i))) {
1721 			return false;
1722 		}
1723 	}
1724 	
1725 	return true;
1726 };
1727 
1728 /**
1729  * Return the ISO-3166 alpha3 equivalent region code for the given ISO 3166 alpha2
1730  * region code. If the given alpha2 code is not found, this function returns its
1731  * argument unchanged.
1732  * @static
1733  * @param {string|undefined} alpha2 the alpha2 code to map
1734  * @return {string|undefined} the alpha3 equivalent of the given alpha2 code, or the alpha2
1735  * parameter if the alpha2 value is not found
1736  */
1737 Locale.regionAlpha2ToAlpha3 = function(alpha2) {
1738 	return Locale.a2toa3regmap[alpha2] || alpha2;
1739 };
1740 
1741 /**
1742  * Return the ISO-639 alpha3 equivalent language code for the given ISO 639 alpha1
1743  * language code. If the given alpha1 code is not found, this function returns its
1744  * argument unchanged.
1745  * @static
1746  * @param {string|undefined} alpha1 the alpha1 code to map
1747  * @return {string|undefined} the alpha3 equivalent of the given alpha1 code, or the alpha1
1748  * parameter if the alpha1 value is not found
1749  */
1750 Locale.languageAlpha1ToAlpha3 = function(alpha1) {
1751 	return Locale.a1toa3langmap[alpha1] || alpha1;
1752 };
1753 
1754 Locale.prototype = {
1755 	/**
1756 	 * @private
1757 	 */
1758 	_genSpec: function () {
1759 		this.spec = this.language || "";
1760 		
1761 		if (this.script) {
1762 			if (this.spec.length > 0) {
1763 				this.spec += "-";
1764 			}
1765 			this.spec += this.script;
1766 		}
1767 		
1768 		if (this.region) {
1769 			if (this.spec.length > 0) {
1770 				this.spec += "-";
1771 			}
1772 			this.spec += this.region;
1773 		}
1774 		
1775 		if (this.variant) {
1776 			if (this.spec.length > 0) {
1777 				this.spec += "-";
1778 			}
1779 			this.spec += this.variant;
1780 		}
1781 	},
1782 
1783 	/**
1784 	 * Return the ISO 639 language code for this locale. 
1785 	 * @return {string|undefined} the language code for this locale 
1786 	 */
1787 	getLanguage: function() {
1788 		return this.language;
1789 	},
1790 	
1791 	/**
1792 	 * Return the language of this locale as an ISO-639-alpha3 language code
1793 	 * @return {string|undefined} the alpha3 language code of this locale
1794 	 */
1795 	getLanguageAlpha3: function() {
1796 		return Locale.languageAlpha1ToAlpha3(this.language);
1797 	},
1798 	
1799 	/**
1800 	 * Return the ISO 3166 region code for this locale.
1801 	 * @return {string|undefined} the region code of this locale
1802 	 */
1803 	getRegion: function() {
1804 		return this.region;
1805 	},
1806 	
1807 	/**
1808 	 * Return the region of this locale as an ISO-3166-alpha3 region code
1809 	 * @return {string|undefined} the alpha3 region code of this locale
1810 	 */
1811 	getRegionAlpha3: function() {
1812 		return Locale.regionAlpha2ToAlpha3(this.region);
1813 	},
1814 	
1815 	/**
1816 	 * Return the ISO 15924 script code for this locale
1817 	 * @return {string|undefined} the script code of this locale
1818 	 */
1819 	getScript: function () {
1820 		return this.script;
1821 	},
1822 	
1823 	/**
1824 	 * Return the variant code for this locale
1825 	 * @return {string|undefined} the variant code of this locale, if any
1826 	 */
1827 	getVariant: function() {
1828 		return this.variant;
1829 	},
1830 	
1831 	/**
1832 	 * Return the whole locale specifier as a string.
1833 	 * @return {string} the locale specifier
1834 	 */
1835 	getSpec: function() {
1836 		return this.spec;
1837 	},
1838 	
1839 	/**
1840 	 * Express this locale object as a string. Currently, this simply calls the getSpec
1841 	 * function to represent the locale as its specifier.
1842 	 * 
1843 	 * @return {string} the locale specifier
1844 	 */
1845 	toString: function() {
1846 		return this.getSpec();
1847 	},
1848 	
1849 	/**
1850 	 * Return true if the the other locale is exactly equal to the current one.
1851 	 * @return {boolean} whether or not the other locale is equal to the current one 
1852 	 */
1853 	equals: function(other) {
1854 		return this.language === other.language &&
1855 			this.region === other.region &&
1856 			this.script === other.script &&
1857 			this.variant === other.variant;
1858 	},
1859 
1860 	/**
1861 	 * Return true if the current locale is the special pseudo locale.
1862 	 * @return {boolean} true if the current locale is the special pseudo locale
1863 	 */
1864 	isPseudo: function () {
1865 		return JSUtils.indexOf(ilib.pseudoLocales, this.spec) > -1;
1866 	}
1867 };
1868 
1869 // static functions
1870 /**
1871  * @private
1872  */
1873 Locale.locales = [
1874 	
1875 ];
1876 
1877 /**
1878  * Return the list of available locales that this iLib file supports.
1879  * If this copy of ilib is pre-assembled with locale data, then the 
1880  * list locales may be much smaller
1881  * than the list of all available locales in the iLib repository. The
1882  * assembly tool will automatically fill in the list for an assembled
1883  * copy of iLib. If this copy is being used with dynamically loaded 
1884  * data, then you 
1885  * can load any locale that iLib supports. You can form a locale with any 
1886  * combination of a language and region tags that exist in the locale
1887  * data directory. Language tags are in the root of the locale data dir,
1888  * and region tags can be found underneath the "und" directory. (The 
1889  * region tags are separated into a different dir because the region names 
1890  * conflict with language names on file systems that are case-insensitive.) 
1891  * If you have culled the locale data directory to limit the size of
1892  * your app, then this function should return only those files that actually exist
1893  * according to the ilibmanifest.json file in the root of that locale
1894  * data dir. Make sure your ilibmanifest.json file is up-to-date with
1895  * respect to the list of files that exist in the locale data dir.
1896  * 
1897  * @param {boolean} sync if false, load the list of available files from disk
1898  * asynchronously, otherwise load them synchronously. (Default: true/synchronously)
1899  * @param {Function} onLoad a callback function to call if asynchronous
1900  * load was requested and the list of files have been loaded.
1901  * @return {Array.<string>} this is an array of locale specs for which 
1902  * this iLib file has locale data for
1903  */
1904 Locale.getAvailableLocales = function (sync, onLoad) {
1905 	var locales = [];
1906 	if (Locale.locales.length || typeof(ilib._load.listAvailableFiles) !== 'function') {
1907 		locales = Locale.locales;
1908 		if (onLoad && typeof(onLoad) === 'function') {
1909 			onLoad(locales);
1910 		}
1911 	} else {
1912 		if (typeof(sync) === 'undefined') {
1913 			sync = true;
1914 		}
1915 		ilib._load.listAvailableFiles(sync, function(manifest) {
1916 			if (manifest) {
1917 				for (var dir in manifest) {
1918 					var filelist = manifest[dir];
1919 					for (var i = 0; i < filelist.length; i++) {
1920 						if (filelist[i].length > 15 && filelist[i].substr(-15) === "localeinfo.json") {
1921 							locales.push(filelist[i].substring(0,filelist[i].length-16).replace(/\//g, "-"));
1922 						}
1923 					}
1924 				}
1925 			}
1926 			if (onLoad && typeof(onLoad) === 'function') {
1927 				onLoad(locales);
1928 			}
1929 		});
1930 	}
1931 	return locales;
1932 };
1933 
1934 
1935 
1936 /*< Utils.js */
1937 /*
1938  * Utils.js - Core utility routines
1939  * 
1940  * Copyright © 2012-2015, JEDLSoft
1941  *
1942  * Licensed under the Apache License, Version 2.0 (the "License");
1943  * you may not use this file except in compliance with the License.
1944  * You may obtain a copy of the License at
1945  *
1946  *     http://www.apache.org/licenses/LICENSE-2.0
1947  *
1948  * Unless required by applicable law or agreed to in writing, software
1949  * distributed under the License is distributed on an "AS IS" BASIS,
1950  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1951  *
1952  * See the License for the specific language governing permissions and
1953  * limitations under the License.
1954  */
1955 
1956 // !depends ilib.js Locale.js JSUtils.js
1957 
1958 
1959 var Utils = {};
1960 
1961 /**
1962  * Find and merge all the locale data for a particular prefix in the given locale
1963  * and return it as a single javascript object. This merges the data in the 
1964  * correct order:
1965  * 
1966  * <ol>
1967  * <li>shared data (usually English)
1968  * <li>data for language
1969  * <li>data for language + region
1970  * <li>data for language + region + script
1971  * <li>data for language + region + script + variant
1972  * </ol>
1973  * 
1974  * It is okay for any of the above to be missing. This function will just skip the 
1975  * missing data. However, if everything except the shared data is missing, this 
1976  * function returns undefined, allowing the caller to go and dynamically load the
1977  * data instead.
1978  * 
1979  * @static
1980  * @param {string} prefix prefix under ilib.data of the data to merge
1981  * @param {Locale} locale locale of the data being sought
1982  * @param {boolean=} replaceArrays if true, replace the array elements in object1 with those in object2.
1983  * If false, concatenate array elements in object1 with items in object2.
1984  * @param {boolean=} returnOne if true, only return the most locale-specific data. If false,
1985  * merge all the relevant locale data together.
1986  * @return {Object?} the merged locale data
1987  */
1988 Utils.mergeLocData = function (prefix, locale, replaceArrays, returnOne) {
1989 	var data = undefined;
1990 	var loc = locale || new Locale();
1991 	var foundLocaleData = false;
1992 	var property = prefix;
1993 	var mostSpecific;
1994 
1995 	data = ilib.data[prefix] || {};
1996 
1997 	mostSpecific = data;
1998 
1999 	if (loc.getLanguage()) {
2000 		property = prefix + '_' + loc.getLanguage();
2001 		if (ilib.data[property]) {
2002 			foundLocaleData = true;
2003 			data = JSUtils.merge(data, ilib.data[property], replaceArrays);
2004 			mostSpecific = ilib.data[property];
2005 		}
2006 	}
2007 	
2008 	if (loc.getRegion()) {
2009 		property = prefix + '_' + loc.getRegion();
2010 		if (ilib.data[property]) {
2011 			foundLocaleData = true;
2012 			data = JSUtils.merge(data, ilib.data[property], replaceArrays);
2013 			mostSpecific = ilib.data[property];
2014 		}
2015 	}
2016 	
2017 	if (loc.getLanguage()) {
2018 		property = prefix + '_' + loc.getLanguage();
2019 		
2020 		if (loc.getScript()) {
2021 			property = prefix + '_' + loc.getLanguage() + '_' + loc.getScript();
2022 			if (ilib.data[property]) {
2023 				foundLocaleData = true;
2024 				data = JSUtils.merge(data, ilib.data[property], replaceArrays);
2025 				mostSpecific = ilib.data[property];
2026 			}
2027 		}
2028 		
2029 		if (loc.getRegion()) {
2030 			property = prefix + '_' + loc.getLanguage() + '_' + loc.getRegion();
2031 			if (ilib.data[property]) {
2032 				foundLocaleData = true;
2033 				data = JSUtils.merge(data, ilib.data[property], replaceArrays);
2034 				mostSpecific = ilib.data[property];
2035 			}
2036 		}		
2037 	}
2038 	
2039 	if (loc.getRegion() && loc.getVariant()) {
2040 		property = prefix + '_' + loc.getLanguage() + '_' + loc.getVariant();
2041 		if (ilib.data[property]) {
2042 			foundLocaleData = true;
2043 			data = JSUtils.merge(data, ilib.data[property], replaceArrays);
2044 			mostSpecific = ilib.data[property];
2045 		}
2046 	}
2047 
2048 	if (loc.getLanguage() && loc.getScript() && loc.getRegion()) {
2049 		property = prefix + '_' + loc.getLanguage() + '_' + loc.getScript() + '_' + loc.getRegion();
2050 		if (ilib.data[property]) {
2051 			foundLocaleData = true;
2052 			data = JSUtils.merge(data, ilib.data[property], replaceArrays);
2053 			mostSpecific = ilib.data[property];
2054 		}
2055 	}
2056 
2057 	if (loc.getLanguage() && loc.getRegion() && loc.getVariant()) {
2058 		property = prefix + '_' + loc.getLanguage() + '_' + loc.getRegion() + '_' + loc.getVariant();
2059 		if (ilib.data[property]) {
2060 			foundLocaleData = true;
2061 			data = JSUtils.merge(data, ilib.data[property], replaceArrays);
2062 			mostSpecific = ilib.data[property];
2063 		}
2064 	}
2065 
2066 	if (loc.getLanguage() && loc.getScript() && loc.getRegion() && loc.getVariant()) {
2067 		property = prefix + '_' + loc.getLanguage() + '_' + loc.getScript() + '_' + loc.getRegion() + '_' + loc.getVariant();
2068 		if (ilib.data[property]) {
2069 			foundLocaleData = true;
2070 			data = JSUtils.merge(data, ilib.data[property], replaceArrays);
2071 			mostSpecific = ilib.data[property];
2072 		}
2073 	}
2074 	
2075 	return foundLocaleData ? (returnOne ? mostSpecific : data) : undefined;
2076 };
2077 
2078 /**
2079  * Return an array of relative path names for the
2080  * files that represent the data for the given locale.<p>
2081  * 
2082  * Note that to prevent the situation where a directory for
2083  * a language exists next to the directory for a region where
2084  * the language code and region code differ only by case, the 
2085  * plain region directories are located under the special 
2086  * "undefined" language directory which has the ISO code "und".
2087  * The reason is that some platforms have case-insensitive 
2088  * file systems, and you cannot have 2 directories with the 
2089  * same name which only differ by case. For example, "es" is
2090  * the ISO 639 code for the language "Spanish" and "ES" is
2091  * the ISO 3166 code for the region "Spain", so both the
2092  * directories cannot exist underneath "locale". The region
2093  * therefore will be loaded from "und/ES" instead.<p>  
2094  * 
2095  * <h4>Variations</h4>
2096  * 
2097  * With only language and region specified, the following
2098  * sequence of paths will be generated:<p>
2099  * 
2100  * <pre>
2101  * language
2102  * und/region
2103  * language/region
2104  * </pre>
2105  * 
2106  * With only language and script specified:<p>
2107  * 
2108  * <pre>
2109  * language
2110  * language/script
2111  * </pre>
2112  * 
2113  * With only script and region specified:<p>
2114  * 
2115  * <pre>
2116  * und/region  
2117  * </pre>
2118  * 
2119  * With only region and variant specified:<p>
2120  * 
2121  * <pre>
2122  * und/region
2123  * region/variant
2124  * </pre>
2125  * 
2126  * With only language, script, and region specified:<p>
2127  * 
2128  * <pre>
2129  * language
2130  * und/region
2131  * language/script
2132  * language/region
2133  * language/script/region
2134  * </pre>
2135  * 
2136  * With only language, region, and variant specified:<p>
2137  * 
2138  * <pre>
2139  * language
2140  * und/region
2141  * language/region
2142  * region/variant
2143  * language/region/variant
2144  * </pre>
2145  * 
2146  * With all parts specified:<p>
2147  * 
2148  * <pre>
2149  * language
2150  * und/region
2151  * language/script
2152  * language/region
2153  * region/variant
2154  * language/script/region
2155  * language/region/variant
2156  * language/script/region/variant
2157  * </pre>
2158  * 
2159  * @static
2160  * @param {Locale} locale load the files for this locale
2161  * @param {string?} name the file name of each file to load without
2162  * any path
2163  * @return {Array.<string>} An array of relative path names
2164  * for the files that contain the locale data
2165  */
2166 Utils.getLocFiles = function(locale, name) {
2167 	var dir = "";
2168 	var files = [];
2169 	var filename = name || "resources.json";
2170 	var loc = locale || new Locale();
2171 	
2172 	var language = loc.getLanguage();
2173 	var region = loc.getRegion();
2174 	var script = loc.getScript();
2175 	var variant = loc.getVariant();
2176 	
2177 	files.push(filename); // generic shared file
2178 	
2179 	if (language) {
2180 		dir = language + "/";
2181 		files.push(dir + filename);
2182 	}
2183 	
2184 	if (region) {
2185 		dir = "und/" + region + "/";
2186 		files.push(dir + filename);
2187 	}
2188 	
2189 	if (language) {
2190 		if (script) {
2191 			dir = language + "/" + script + "/";
2192 			files.push(dir + filename);
2193 		}
2194 		if (region) {
2195 			dir = language + "/" + region + "/";
2196 			files.push(dir + filename);
2197 		}
2198 	}
2199 	
2200 	if (region && variant) {
2201 		dir = "und/" + region + "/" + variant + "/";
2202 		files.push(dir + filename);
2203 	}
2204 
2205 	if (language && script && region) {
2206 		dir = language + "/" + script + "/" + region + "/";
2207 		files.push(dir + filename);
2208 	}
2209 
2210 	if (language && region && variant) {
2211 		dir = language + "/" + region + "/" + variant + "/";
2212 		files.push(dir + filename);
2213 	}
2214 
2215 	if (language && script && region && variant) {
2216 		dir = language + "/" + script + "/" + region + "/" + variant + "/";
2217 		files.push(dir + filename);
2218 	}
2219 	
2220 	return files;
2221 };
2222 
2223 /**
2224  * Load data using the new loader object or via the old function callback.
2225  * @static
2226  * @private
2227  */
2228 Utils._callLoadData = function (files, sync, params, callback) {
2229 	// console.log("Utils._callLoadData called");
2230 	if (typeof(ilib._load) === 'function') {
2231 		// console.log("Utils._callLoadData: calling as a regular function");
2232 		return ilib._load(files, sync, params, callback);
2233 	} else if (typeof(ilib._load) === 'object' && typeof(ilib._load.loadFiles) === 'function') {
2234 		// console.log("Utils._callLoadData: calling as an object");
2235 		return ilib._load.loadFiles(files, sync, params, callback);
2236 	}
2237 	
2238 	// console.log("Utils._callLoadData: not calling. Type is " + typeof(ilib._load) + " and instanceof says " + (ilib._load instanceof Loader));
2239 	return undefined;
2240 };
2241 
2242 /**
2243  * Find locale data or load it in. If the data with the given name is preassembled, it will
2244  * find the data in ilib.data. If the data is not preassembled but there is a loader function,
2245  * this function will call it to load the data. Otherwise, the callback will be called with
2246  * undefined as the data. This function will create a cache under the given class object.
2247  * If data was successfully loaded, it will be set into the cache so that future access to 
2248  * the same data for the same locale is much quicker.<p>
2249  * 
2250  * The parameters can specify any of the following properties:<p>
2251  * 
2252  * <ul>
2253  * <li><i>name</i> - String. The name of the file being loaded. Default: ResBundle.json
2254  * <li><i>object</i> - Object. The class attempting to load data. The cache is stored inside of here.
2255  * <li><i>locale</i> - Locale. The locale for which data is loaded. Default is the current locale.
2256  * <li><i>nonlocale</i> - boolean. If true, the data being loaded is not locale-specific.
2257  * <li><i>type</i> - String. Type of file to load. This can be "json" or "other" type. Default: "json" 
2258  * <li><i>replace</i> - boolean. When merging json objects, this parameter controls whether to merge arrays
2259  * or have arrays replace each other. If true, arrays in child objects replace the arrays in parent 
2260  * objects. When false, the arrays in child objects are concatenated with the arrays in parent objects.  
2261  * <li><i>loadParams</i> - Object. An object with parameters to pass to the loader function
2262  * <li><i>sync</i> - boolean. Whether or not to load the data synchronously
2263  * <li><i>callback</i> - function(?)=. callback Call back function to call when the data is available.
2264  * Data is not returned from this method, so a callback function is mandatory.
2265  * </ul>
2266  * 
2267  * @static
2268  * @param {Object} params Parameters configuring how to load the files (see above)
2269  */
2270 Utils.loadData = function(params) {
2271 	var name = "resources.json",
2272 		object = undefined, 
2273 		locale = new Locale(ilib.getLocale()), 
2274 		sync = false, 
2275 		type = undefined,
2276 		loadParams = {},
2277 		callback = undefined,
2278 		nonlocale = false,
2279 		replace = false,
2280 		basename;
2281 	
2282 	if (!params || typeof(params.callback) !== 'function') {
2283 		return;
2284 	}
2285 
2286 	if (params.name) {
2287 		name = params.name;
2288 	}
2289 	if (params.object) {
2290 		object = params.object;
2291 	}
2292 	if (params.locale) {
2293 		locale = (typeof(params.locale) === 'string') ? new Locale(params.locale) : params.locale;
2294 	}			
2295 	if (params.type) {
2296 		type = params.type;
2297 	}
2298 	if (params.loadParams) {
2299 		loadParams = params.loadParams;
2300 	}
2301 	if (params.sync) {
2302 		sync = params.sync;
2303 	}
2304 	if (params.nonlocale) {
2305 		nonlocale = !!params.nonlocale;
2306 	}
2307 	if (typeof(params.replace) === 'boolean') {
2308 		replace = params.replace;
2309 	}
2310 	
2311 	callback = params.callback;
2312 	
2313 	if (object && !object.cache) {
2314 		object.cache = {};
2315 	}
2316 	
2317 	if (!type) {
2318 		var dot = name.lastIndexOf(".");
2319 		type = (dot !== -1) ? name.substring(dot+1) : "text";
2320 	}
2321 
2322 	var spec = ((!nonlocale && locale.getSpec().replace(/-/g, '_')) || "root") + "," + name + "," + String(JSUtils.hashCode(loadParams));
2323 	if (!object || typeof(object.cache[spec]) === 'undefined') {
2324 		var data, returnOne = (loadParams && loadParams.returnOne);
2325 		
2326 		if (type === "json") {
2327 			// console.log("type is json");
2328 			basename = name.substring(0, name.lastIndexOf("."));
2329 			if (nonlocale) {
2330 				basename = basename.replace(/[\.:\(\)\/\\\+\-]/g, "_");
2331 				data = ilib.data[basename];
2332 			} else {
2333 				data = Utils.mergeLocData(basename, locale, replace, returnOne);
2334 			}
2335 			if (data) {
2336 				// console.log("found assembled data");
2337 				if (object) {
2338 					object.cache[spec] = data;
2339 				}
2340 				callback(data);
2341 				return;
2342 			}
2343 		}
2344 		
2345 		// console.log("ilib._load is " + typeof(ilib._load));
2346 		if (typeof(ilib._load) !== 'undefined') {
2347 			// the data is not preassembled, so attempt to load it dynamically
2348 			var files = nonlocale ? [ name || "resources.json" ] : Utils.getLocFiles(locale, name);
2349 			if (type !== "json") {
2350 				loadParams.returnOne = true;
2351 			}
2352 			
2353 			Utils._callLoadData(files, sync, loadParams, ilib.bind(this, function(arr) {
2354 				if (type === "json") {
2355 					data = ilib.data[basename] || {};
2356 					for (var i = 0; i < arr.length; i++) {
2357 						if (typeof(arr[i]) !== 'undefined') {
2358 							data = loadParams.returnOne ? arr[i] : JSUtils.merge(data, arr[i], replace);
2359 						}
2360 					}
2361 					
2362 					if (object) {
2363 						object.cache[spec] = data;
2364 					}
2365 					callback(data);
2366 				} else {
2367 					var i = arr.length-1; 
2368 					while (i > -1 && !arr[i]) {
2369 						i--;
2370 					}
2371 					if (i > -1) {
2372 						if (object) {
2373 							object.cache[spec] = arr[i];
2374 						}
2375 						callback(arr[i]);
2376 					} else {
2377 						callback(undefined);
2378 					}
2379 				}
2380 			}));
2381 		} else {
2382 			// no data other than the generic shared data
2383 			if (type === "json") {
2384 				data = ilib.data[basename];
2385 			}
2386 			if (object && data) {
2387 				object.cache[spec] = data;
2388 			}
2389 			callback(data);
2390 		}
2391 	} else {
2392 		callback(object.cache[spec]);
2393 	}
2394 };
2395 
2396 
2397 /*< LocaleInfo.js */
2398 /*
2399  * LocaleInfo.js - Encode locale-specific defaults
2400  * 
2401  * Copyright © 2012-2015, JEDLSoft
2402  *
2403  * Licensed under the Apache License, Version 2.0 (the "License");
2404  * you may not use this file except in compliance with the License.
2405  * You may obtain a copy of the License at
2406  *
2407  *     http://www.apache.org/licenses/LICENSE-2.0
2408  *
2409  * Unless required by applicable law or agreed to in writing, software
2410  * distributed under the License is distributed on an "AS IS" BASIS,
2411  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2412  *
2413  * See the License for the specific language governing permissions and
2414  * limitations under the License.
2415  */
2416 
2417 // !depends ilib.js Locale.js Utils.js
2418 
2419 // !data localeinfo
2420 
2421 
2422 /**
2423  * @class
2424  * Create a new locale info instance. Locale info instances give information about
2425  * the default settings for a particular locale. These settings may be overridden
2426  * by various parts of the code, and should be used as a fall-back setting of last
2427  * resort. <p>
2428  * 
2429  * The optional options object holds extra parameters if they are necessary. The
2430  * current list of supported options are:
2431  * 
2432  * <ul>
2433  * <li><i>onLoad</i> - a callback function to call when the locale info object is fully 
2434  * loaded. When the onLoad option is given, the localeinfo object will attempt to
2435  * load any missing locale data using the ilib loader callback.
2436  * When the constructor is done (even if the data is already preassembled), the 
2437  * onLoad function is called with the current instance as a parameter, so this
2438  * callback can be used with preassembled or dynamic loading or a mix of the two.
2439  * 
2440  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
2441  * asynchronously. If this option is given as "false", then the "onLoad"
2442  * callback must be given, as the instance returned from this constructor will
2443  * not be usable for a while. 
2444  *
2445  * <li><i>loadParams</i> - an object containing parameters to pass to the 
2446  * loader callback function when locale data is missing. The parameters are not
2447  * interpretted or modified in any way. They are simply passed along. The object 
2448  * may contain any property/value pairs as long as the calling code is in
2449  * agreement with the loader callback function as to what those parameters mean.
2450  * </ul>
2451  * 
2452  * If this copy of ilib is pre-assembled and all the data is already available, 
2453  * or if the data was already previously loaded, then this constructor will call
2454  * the onLoad callback immediately when the initialization is done. 
2455  * If the onLoad option is not given, this class will only attempt to load any
2456  * missing locale data synchronously.
2457  * 
2458  * 
2459  * @constructor
2460  * @see {ilib.setLoaderCallback} for information about registering a loader callback
2461  * function
2462  * @param {Locale|string=} locale the locale for which the info is sought, or undefined for
2463  * @param {Object=} options the locale for which the info is sought, or undefined for
2464  * the current locale
2465  */
2466 var LocaleInfo = function(locale, options) {
2467 	var sync = true,
2468 	    loadParams = undefined;
2469 	
2470 	/**
2471 	  @private 
2472 	  @type {{
2473 		calendar:string,
2474 		clock:string,
2475 		currency:string,
2476 		delimiter: {quotationStart:string,quotationEnd:string,alternateQuotationStart:string,alternateQuotationEnd:string},
2477 		firstDayOfWeek:number,
2478 		meridiems:string,
2479 		numfmt:{
2480 			currencyFormats:{common:string,commonNegative:string,iso:string,isoNegative:string},
2481 			decimalChar:string,
2482 			exponential:string,
2483 			groupChar:string,
2484 			negativenumFmt:string,
2485 			negativepctFmt:string,
2486 			pctChar:string,
2487 			pctFmt:string,
2488 			prigroupSize:number,
2489 			roundingMode:string,
2490 			script:string,
2491 			secgroupSize:number
2492 		},
2493 		timezone:string,
2494 		units:string,
2495 		weekendEnd:number,
2496 		weekendStart:number,
2497 		paperSizes:{regular:string}
2498 	  }}
2499 	*/
2500 	this.info = LocaleInfo.defaultInfo;
2501 	
2502 	switch (typeof(locale)) {
2503 		case "string":
2504 			this.locale = new Locale(locale);
2505 			break;
2506 		default:
2507 		case "undefined":
2508 			this.locale = new Locale();
2509 			break;
2510 		case "object":
2511 			this.locale = locale;
2512 			break;
2513 	}
2514 	
2515 	if (options) {
2516 		if (typeof(options.sync) !== 'undefined') {
2517 			sync = (options.sync == true);
2518 		}
2519 		
2520 		if (typeof(options.loadParams) !== 'undefined') {
2521 			loadParams = options.loadParams;
2522 		}
2523 	}
2524 
2525 	if (!LocaleInfo.cache) {
2526 		LocaleInfo.cache = {};
2527 	}
2528 
2529 	Utils.loadData({
2530 		object: LocaleInfo, 
2531 		locale: this.locale, 
2532 		name: "localeinfo.json", 
2533 		sync: sync, 
2534 		loadParams: loadParams, 
2535 		callback: ilib.bind(this, function (info) {
2536 			if (!info) {
2537 				info = LocaleInfo.defaultInfo;
2538 				var spec = this.locale.getSpec().replace(/-/g, "_");
2539 				LocaleInfo.cache[spec] = info;
2540 			}
2541 			this.info = info;
2542 			if (options && typeof(options.onLoad) === 'function') {
2543 				options.onLoad(this);
2544 			}
2545 		})
2546 	});
2547 };
2548 
2549 LocaleInfo.defaultInfo = ilib.data.localeinfo;
2550 LocaleInfo.defaultInfo = LocaleInfo.defaultInfo || {
2551 	"calendar": "gregorian",
2552 	"clock": "24",
2553 	"currency": "USD",
2554 	"delimiter": {
2555     	"quotationStart": "“",
2556     	"quotationEnd": "”",
2557     	"alternateQuotationStart": "‘",
2558     	"alternateQuotationEnd": "’"
2559     },
2560     "firstDayOfWeek": 1,
2561     "meridiems": "gregorian",
2562     "numfmt": {
2563         "currencyFormats": {
2564             "common": "{s}{n}",
2565             "commonNegative": "({s}{n})",
2566             "iso": "{s}{n}",
2567             "isoNegative": "({s}{n})"
2568         },
2569         "decimalChar": ".",
2570         "exponential": "E",
2571         "groupChar": ",",
2572         "negativenumFmt": "-{n}",
2573         "negativepctFmt": "-{n}%",
2574         "pctChar": "%",
2575         "pctFmt": "{n}%",
2576         "prigroupSize": 3,
2577         "roundingMode": "halfdown",
2578         "script": "Latn",
2579         "secgroupSize": 0,
2580         "useNative": false
2581     },
2582     "timezone": "Etc/UTC",
2583     "units": "metric",
2584     "weekendStart": 6,
2585     "weekendEnd": 0
2586 };
2587 
2588 LocaleInfo.prototype = {
2589     /**
2590      * Return the name of the locale's language in English.
2591      * @returns {string} the name of the locale's language in English
2592      */
2593     getLanguageName: function () {
2594     	return this.info["language.name"];	
2595     },
2596     
2597     /**
2598      * Return the name of the locale's region in English. If the locale
2599      * has no region, this returns undefined.
2600      * 
2601      * @returns {string|undefined} the name of the locale's region in English
2602      */
2603     getRegionName: function () {
2604     	return this.info["region.name"];	
2605     },
2606 
2607     /**
2608 	 * Return whether this locale commonly uses the 12- or the 24-hour clock.
2609 	 *  
2610 	 * @returns {string} "12" if the locale commonly uses a 12-hour clock, or "24"
2611 	 * if the locale commonly uses a 24-hour clock. 
2612 	 */
2613 	getClock: function() {
2614 		return this.info.clock;
2615 	},
2616 
2617 	/**
2618 	 * Return the locale that this info object was created with.
2619 	 * @returns {Locale} The locale spec of the locale used to construct this info instance
2620 	 */
2621 	getLocale: function () {
2622 		return this.locale;
2623 	},
2624 	
2625 	/**
2626 	 * Return the name of the measuring system that is commonly used in the given locale.
2627 	 * Valid values are "uscustomary", "imperial", and "metric".
2628 	 * 
2629 	 * @returns {string} The name of the measuring system commonly used in the locale
2630 	 */
2631 	getUnits: function () {
2632 		return this.info.units;
2633 	},
2634 	
2635 	/**
2636 	 * Return the name of the calendar that is commonly used in the given locale.
2637 	 * 
2638 	 * @returns {string} The name of the calendar commonly used in the locale
2639 	 */
2640 	getCalendar: function () {
2641 		return this.info.calendar;
2642 	},
2643 	
2644 	/**
2645 	 * Return the day of week that starts weeks in the current locale. Days are still
2646 	 * numbered the standard way with 0 for Sunday through 6 for Saturday, but calendars 
2647 	 * should be displayed and weeks calculated with the day of week returned from this 
2648 	 * function as the first day of the week.
2649 	 * 
2650 	 * @returns {number} the day of the week that starts weeks in the current locale.
2651 	 */
2652 	getFirstDayOfWeek: function () {
2653 		return this.info.firstDayOfWeek;
2654 	},
2655 	
2656 	/**
2657 	 * Return the day of week that starts weekend in the current locale. Days are still
2658 	 * numbered the standard way with 0 for Sunday through 6 for Saturday.
2659 	 * 
2660 	 * @returns {number} the day of the week that starts weeks in the current locale.
2661 	 */
2662 	getWeekEndStart: function () {
2663 		return this.info.weekendStart;
2664 	},
2665 
2666 	/**
2667 	 * Return the day of week that starts weekend in the current locale. Days are still
2668 	 * numbered the standard way with 0 for Sunday through 6 for Saturday.
2669 	 * 
2670 	 * @returns {number} the day of the week that starts weeks in the current locale.
2671 	 */
2672 	getWeekEndEnd: function () {
2673 		return this.info.weekendEnd;
2674 	},
2675 
2676 	/**
2677 	 * Return the default time zone for this locale. Many locales span across multiple
2678 	 * time zones. In this case, the time zone with the largest population is chosen
2679 	 * to represent the locale. This is obviously not that accurate, but then again,
2680 	 * this method's return value should only be used as a default anyways.
2681 	 * @returns {string} the default time zone for this locale.
2682 	 */
2683 	getTimeZone: function () {
2684 		return this.info.timezone;
2685 	},
2686 	
2687 	/**
2688 	 * Return the decimal separator for formatted numbers in this locale.
2689 	 * @returns {string} the decimal separator char
2690 	 */
2691 	getDecimalSeparator: function () {
2692 		return this.info.numfmt.decimalChar;
2693 	},
2694 	
2695 	/**
2696 	 * Return the decimal separator for formatted numbers in this locale for native script.
2697 	 * @returns {string} the decimal separator char
2698 	 */
2699 	getNativeDecimalSeparator: function () {
2700 		return (this.info.native_numfmt && this.info.native_numfmt.decimalChar) || this.info.numfmt.decimalChar;
2701 	},
2702 	
2703 	/**
2704 	 * Return the separator character used to separate groups of digits on the 
2705 	 * integer side of the decimal character.
2706 	 * @returns {string} the grouping separator char
2707 	 */
2708 	getGroupingSeparator: function () {
2709 		return this.info.numfmt.groupChar;
2710 	},
2711 
2712 	/**
2713 	 * Return the separator character used to separate groups of digits on the 
2714 	 * integer side of the decimal character for the native script if present other than the default script.
2715 	 * @returns {string} the grouping separator char
2716 	 */
2717 	getNativeGroupingSeparator: function () {
2718 		return (this.info.native_numfmt && this.info.native_numfmt.groupChar) || this.info.numfmt.groupChar;
2719 	},
2720 	
2721 	/**
2722 	 * Return the minimum number of digits grouped together on the integer side 
2723 	 * for the first (primary) group. 
2724 	 * In western European cultures, groupings are in 1000s, so the number of digits
2725 	 * is 3. 
2726 	 * @returns {number} the number of digits in a primary grouping, or 0 for no grouping
2727 	 */
2728 	getPrimaryGroupingDigits: function () {
2729 		return (typeof(this.info.numfmt.prigroupSize) !== 'undefined' && this.info.numfmt.prigroupSize) || 0;
2730 	},
2731 
2732 	/**
2733 	 * Return the minimum number of digits grouped together on the integer side
2734 	 * for the second or more (secondary) group.<p>
2735 	 *   
2736 	 * In western European cultures, all groupings are by 1000s, so the secondary
2737 	 * size should be 0 because there is no secondary size. In general, if this 
2738 	 * method returns 0, then all groupings are of the primary size.<p> 
2739 	 * 
2740 	 * For some other cultures, the first grouping (primary)
2741 	 * is 3 and any subsequent groupings (secondary) are two. So, 100000 would be
2742 	 * written as: "1,00,000".
2743 	 * 
2744 	 * @returns {number} the number of digits in a secondary grouping, or 0 for no 
2745 	 * secondary grouping. 
2746 	 */
2747 	getSecondaryGroupingDigits: function () {
2748 		return this.info.numfmt.secgroupSize || 0;
2749 	},
2750 
2751 	/**
2752 	 * Return the format template used to format percentages in this locale.
2753 	 * @returns {string} the format template for formatting percentages
2754 	 */
2755 	getPercentageFormat: function () {
2756 		return this.info.numfmt.pctFmt;
2757 	},
2758 
2759 	/**
2760 	 * Return the format template used to format percentages in this locale
2761 	 * with negative amounts.
2762 	 * @returns {string} the format template for formatting percentages
2763 	 */
2764 	getNegativePercentageFormat: function () {
2765 		return this.info.numfmt.negativepctFmt;
2766 	},
2767 
2768 	/**
2769 	 * Return the symbol used for percentages in this locale.
2770 	 * @returns {string} the symbol used for percentages in this locale
2771 	 */
2772 	getPercentageSymbol: function () {
2773 		return this.info.numfmt.pctChar || "%";
2774 	},
2775 
2776 	/**
2777 	 * Return the symbol used for exponential in this locale.
2778 	 * @returns {string} the symbol used for exponential in this locale
2779 	 */
2780 	getExponential: function () {
2781 		return this.info.numfmt.exponential;
2782 	},
2783 
2784 	/**
2785 	 * Return the symbol used for exponential in this locale for native script.
2786 	 * @returns {string} the symbol used for exponential in this locale for native script
2787 	 */
2788 	getNativeExponential: function () {
2789 		return (this.info.native_numfmt && this.info.native_numfmt.exponential) || this.info.numfmt.exponential;
2790 	},
2791 
2792 	/**
2793 	 * Return the symbol used for percentages in this locale for native script.
2794 	 * @returns {string} the symbol used for percentages in this locale for native script
2795 	 */
2796 	getNativePercentageSymbol: function () {
2797 		return (this.info.native_numfmt && this.info.native_numfmt.pctChar) || this.info.numfmt.pctChar || "%";
2798 	
2799 	},
2800 	/**
2801 	 * Return the format template used to format negative numbers in this locale.
2802 	 * @returns {string} the format template for formatting negative numbers
2803 	 */
2804 	getNegativeNumberFormat: function () { 
2805 		return this.info.numfmt.negativenumFmt;
2806 	},
2807 	
2808 	/**
2809 	 * Return an object containing the format templates for formatting currencies
2810 	 * in this locale. The object has a number of properties in it that each are
2811 	 * a particular style of format. Normally, this contains a "common" and an "iso"
2812 	 * style, but may contain others in the future.
2813 	 * @returns {Object} an object containing the format templates for currencies
2814 	 */
2815 	getCurrencyFormats: function () {
2816 		return this.info.numfmt.currencyFormats;
2817 	},
2818 	
2819 	/**
2820 	 * Return the currency that is legal in the locale, or which is most commonly 
2821 	 * used in regular commerce.
2822 	 * @returns {string} the ISO 4217 code for the currency of this locale
2823 	 */
2824 	getCurrency: function () {
2825 		return this.info.currency;
2826 	},
2827 	
2828 	/**
2829 	 * Return a string that describes the style of digits used by this locale.
2830 	 * Possible return values are:
2831 	 * <ul>
2832 	 * <li><i>western</i> - uses the regular western 10-based digits 0 through 9
2833 	 * <li><i>optional</i> - native 10-based digits exist, but in modern usage,
2834 	 * this locale most often uses western digits
2835 	 * <li><i>native</i> - native 10-based native digits exist and are used
2836 	 * regularly by this locale
2837 	 * <li><i>custom</i> - uses native digits by default that are not 10-based
2838 	 * </ul>
2839 	 * @returns {string} string that describes the style of digits used in this locale
2840 	 */
2841 	getDigitsStyle: function () {
2842 		if (this.info.numfmt.useNative) {
2843 			return "native";
2844 		}
2845 		if (typeof(this.info.native_numfmt) !== 'undefined') {
2846 			return "optional";
2847 		}
2848 		return "western";
2849 	},
2850 	
2851 	/**
2852 	 * Return the digits of the default script if they are defined.
2853 	 * If not defined, the default should be the regular "Arabic numerals"
2854 	 * used in the Latin script. (0-9)
2855 	 * @returns {string|undefined} the digits used in the default script 
2856 	 */
2857 	getDigits: function () {
2858 		return this.info.numfmt.digits;
2859 	},
2860 	
2861 	/**
2862 	 * Return the digits of the native script if they are defined. 
2863 	 * @returns {string|undefined} the digits used in the default script 
2864 	 */
2865 	getNativeDigits: function () {
2866 		return (this.info.numfmt.useNative && this.info.numfmt.digits) || (this.info.native_numfmt && this.info.native_numfmt.digits);
2867 	},
2868 	
2869 	/**
2870 	 * If this locale typically uses a different type of rounding for numeric
2871 	 * formatting other than halfdown, especially for currency, then it can be 
2872 	 * specified in the localeinfo. If the locale uses the default, then this 
2873 	 * method returns undefined. The locale's rounding method overrides the 
2874 	 * rounding method for the currency itself, which can sometimes shared 
2875 	 * between various locales so it is less specific.
2876 	 * @returns {string} the name of the rounding mode typically used in this
2877 	 * locale, or "halfdown" if the locale does not override the default
2878 	 */
2879 	getRoundingMode: function () {
2880 		return this.info.numfmt.roundingMode;
2881 	},
2882 	
2883 	/**
2884 	 * Return the default script used to write text in the language of this 
2885 	 * locale. Text for most languages is written in only one script, but there
2886 	 * are some languages where the text can be written in a number of scripts,
2887 	 * depending on a variety of things such as the region, ethnicity, religion, 
2888 	 * etc. of the author. This method returns the default script for the
2889 	 * locale, in which the language is most commonly written.<p> 
2890 	 * 
2891 	 * The script is returned as an ISO 15924 4-letter code.
2892 	 * 
2893 	 * @returns {string} the ISO 15924 code for the default script used to write
2894 	 * text in this locale 
2895 	 */
2896 	getDefaultScript: function() {
2897 		return (this.info.scripts) ? this.info.scripts[0] : "Latn";
2898 	},
2899 	
2900 	/**
2901 	 * Return the script used for the current locale. If the current locale
2902 	 * explicitly defines a script, then this script is returned. If not, then 
2903 	 * the default script for the locale is returned.
2904 	 * 
2905 	 * @see LocaleInfo.getDefaultScript
2906 	 * @returns {string} the ISO 15924 code for the script used to write
2907 	 * text in this locale
2908 	 */
2909 	getScript: function() {
2910 		return this.locale.getScript() || this.getDefaultScript(); 
2911 	},
2912 	
2913 	/**
2914 	 * Return an array of script codes which are used to write text in the current
2915 	 * language. Text for most languages is written in only one script, but there
2916 	 * are some languages where the text can be written in a number of scripts,
2917 	 * depending on a variety of things such as the region, ethnicity, religion, 
2918 	 * etc. of the author. This method returns an array of script codes in which 
2919 	 * the language is commonly written.
2920 	 * 
2921 	 * @returns {Array.<string>} an array of ISO 15924 codes for the scripts used 
2922 	 * to write text in this language
2923 	 */
2924 	getAllScripts: function() {
2925 		return this.info.scripts || ["Latn"];
2926 	},
2927 	
2928 	/**
2929 	 * Return the default style of meridiems used in this locale. Meridiems are 
2930 	 * times of day like AM/PM. In a few locales with some calendars, for example
2931 	 * Amharic/Ethiopia using the Ethiopic calendar, the times of day may be
2932 	 * split into different segments than simple AM/PM as in the Gregorian 
2933 	 * calendar. Only a few locales are like that. For most locales, formatting 
2934 	 * a Gregorian date will use the regular Gregorian AM/PM meridiems.
2935 	 *  
2936 	 * @returns {string} the default meridiems style used in this locale. Possible
2937 	 * values are "gregorian", "chinese", and "ethiopic"
2938 	 */
2939 	getMeridiemsStyle: function () {
2940 		return this.info.meridiems || "gregorian";
2941 	},	
2942 	/**
2943 	 * Return the default PaperSize information in this locale.
2944 	 * @returns {string} default PaperSize in this locale
2945 	 */
2946 	getPaperSize: function () {
2947 		return this.info.paperSizes.regular;
2948 	},
2949 	/**
2950 	 * Return the default Delimiter QuotationStart information in this locale.
2951 	 * @returns {string} default QuotationStart in this locale
2952 	 */
2953 	getDelimiterQuotationStart: function () {
2954 		return this.info.delimiter.quotationStart;
2955 	},
2956 	/**
2957 	 * Return the default Delimiter QuotationEnd information in this locale.
2958 	 * @returns {string} default QuotationEnd in this locale
2959 	 */
2960 	getDelimiterQuotationEnd: function () {
2961 		return this.info.delimiter.quotationEnd;
2962 	}
2963 };
2964 
2965 
2966 
2967 /*< IDate.js */
2968 /*
2969  * IDate.js - Represent a date in any calendar. This class is subclassed for each 
2970  * calendar and includes some shared functionality.
2971  * 
2972  * Copyright © 2012-2015, JEDLSoft
2973  *
2974  * Licensed under the Apache License, Version 2.0 (the "License");
2975  * you may not use this file except in compliance with the License.
2976  * You may obtain a copy of the License at
2977  *
2978  *     http://www.apache.org/licenses/LICENSE-2.0
2979  *
2980  * Unless required by applicable law or agreed to in writing, software
2981  * distributed under the License is distributed on an "AS IS" BASIS,
2982  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2983  *
2984  * See the License for the specific language governing permissions and
2985  * limitations under the License.
2986  */
2987 
2988 /* !depends LocaleInfo.js */
2989 
2990 
2991 /**
2992  * @class
2993  * Superclass for all the calendar date classes that contains shared 
2994  * functionality. This class is never instantiated on its own. Instead,
2995  * you should use the {@link DateFactory} function to manufacture a new
2996  * instance of a subclass of IDate. This class is called IDate for "ilib
2997  * date" so that it does not conflict with the built-in Javascript Date
2998  * class.
2999  * 
3000  * @private
3001  * @constructor
3002  * @param {Object=} options The date components to initialize this date with
3003  */
3004 var IDate = function(options) {
3005 };
3006 
3007 /* place for the subclasses to put their constructors so that the factory method
3008  * can find them. Do this to add your date after it's defined: 
3009  * IDate._constructors["mytype"] = IDate.MyTypeConstructor;
3010  */
3011 IDate._constructors = {};
3012 
3013 IDate.prototype = {
3014 	getType: function() {
3015 		return "date";
3016 	},
3017 	
3018 	/**
3019 	 * Return the unix time equivalent to this date instance. Unix time is
3020 	 * the number of milliseconds since midnight on Jan 1, 1970 UTC (Gregorian). This 
3021 	 * method only returns a valid number for dates between midnight, 
3022 	 * Jan 1, 1970 UTC (Gregorian) and Jan 19, 2038 at 3:14:07am UTC (Gregorian) when 
3023 	 * the unix time runs out. If this instance encodes a date outside of that range, 
3024 	 * this method will return -1. For date types that are not Gregorian, the point 
3025 	 * in time represented by this date object will only give a return value if it
3026 	 * is in the correct range in the Gregorian calendar as given previously.
3027 	 * 
3028 	 * @return {number} a number giving the unix time, or -1 if the date is outside the
3029 	 * valid unix time range
3030 	 */
3031 	getTime: function() {
3032 		return this.rd.getTime(); 
3033 	},
3034 	
3035 	/**
3036 	 * Return the extended unix time equivalent to this Gregorian date instance. Unix time is
3037 	 * the number of milliseconds since midnight on Jan 1, 1970 UTC. Traditionally unix time
3038 	 * (or the type "time_t" in C/C++) is only encoded with an unsigned 32 bit integer, and thus 
3039 	 * runs out on Jan 19, 2038. However, most Javascript engines encode numbers well above 
3040 	 * 32 bits and the Date object allows you to encode up to 100 million days worth of time 
3041 	 * after Jan 1, 1970, and even more interestingly, 100 million days worth of time before
3042 	 * Jan 1, 1970 as well. This method returns the number of milliseconds in that extended 
3043 	 * range. If this instance encodes a date outside of that range, this method will return
3044 	 * NaN.
3045 	 * 
3046 	 * @return {number} a number giving the extended unix time, or Nan if the date is outside 
3047 	 * the valid extended unix time range
3048 	 */
3049 	getTimeExtended: function() {
3050 		return this.rd.getTimeExtended();
3051 	},
3052 
3053 	/**
3054 	 * Set the time of this instance according to the given unix time. Unix time is
3055 	 * the number of milliseconds since midnight on Jan 1, 1970.
3056 	 * 
3057 	 * @param {number} millis the unix time to set this date to in milliseconds 
3058 	 */
3059 	setTime: function(millis) {
3060 		this.rd = this.newRd({
3061 			unixtime: millis,
3062 			cal: this.cal
3063 		});
3064 		this._calcDateComponents();
3065 	},
3066 	
3067 	getDays: function() {
3068 		return this.day;
3069 	},
3070 	getMonths: function() {
3071 		return this.month;
3072 	},
3073 	getYears: function() {
3074 		return this.year;
3075 	},
3076 	getHours: function() {
3077 		return this.hour;
3078 	},
3079 	getMinutes: function() {
3080 		return this.minute;
3081 	},
3082 	getSeconds: function() {
3083 		return this.second;
3084 	},
3085 	getMilliseconds: function() {
3086 		return this.millisecond;
3087 	},
3088 	getEra: function() {
3089 		return (this.year < 1) ? -1 : 1;
3090 	},
3091 
3092 	setDays: function(day) {
3093 		this.day = parseInt(day, 10) || 1;
3094 		this.rd._setDateComponents(this);
3095 	},
3096 	setMonths: function(month) {
3097 		this.month = parseInt(month, 10) || 1;
3098 		this.rd._setDateComponents(this);
3099 	},
3100 	setYears: function(year) {
3101 		this.year = parseInt(year, 10) || 0;
3102 		this.rd._setDateComponents(this);
3103 	},
3104 	
3105 	setHours: function(hour) {
3106 		this.hour = parseInt(hour, 10) || 0;
3107 		this.rd._setDateComponents(this);
3108 	},
3109 	setMinutes: function(minute) {
3110 		this.minute = parseInt(minute, 10) || 0;
3111 		this.rd._setDateComponents(this);
3112 	},
3113 	setSeconds: function(second) {
3114 		this.second = parseInt(second, 10) || 0;
3115 		this.rd._setDateComponents(this);
3116 	},
3117 	setMilliseconds: function(milli) {
3118 		this.millisecond = parseInt(milli, 10) || 0;
3119 		this.rd._setDateComponents(this);
3120 	},
3121 	
3122 	/**
3123 	 * Return a new date instance in the current calendar that represents the first instance 
3124 	 * of the given day of the week before the current date. The day of the week is encoded
3125 	 * as a number where 0 = Sunday, 1 = Monday, etc.
3126 	 * 
3127 	 * @param {number} dow the day of the week before the current date that is being sought
3128 	 * @return {IDate} the date being sought
3129 	 */
3130 	before: function (dow) {
3131 		return new this.constructor({
3132 			rd: this.rd.before(dow, this.offset),
3133 			timezone: this.timezone
3134 		});
3135 	},
3136 	
3137 	/**
3138 	 * Return a new date instance in the current calendar that represents the first instance 
3139 	 * of the given day of the week after the current date. The day of the week is encoded
3140 	 * as a number where 0 = Sunday, 1 = Monday, etc.
3141 	 * 
3142 	 * @param {number} dow the day of the week after the current date that is being sought
3143 	 * @return {IDate} the date being sought
3144 	 */
3145 	after: function (dow) {
3146 		return new this.constructor({
3147 			rd: this.rd.after(dow, this.offset),
3148 			timezone: this.timezone
3149 		});
3150 	},
3151 
3152 	/**
3153 	 * Return a new Gregorian date instance that represents the first instance of the 
3154 	 * given day of the week on or before the current date. The day of the week is encoded
3155 	 * as a number where 0 = Sunday, 1 = Monday, etc.
3156 	 * 
3157 	 * @param {number} dow the day of the week on or before the current date that is being sought
3158 	 * @return {IDate} the date being sought
3159 	 */
3160 	onOrBefore: function (dow) {
3161 		return new this.constructor({
3162 			rd: this.rd.onOrBefore(dow, this.offset),
3163 			timezone: this.timezone
3164 		});
3165 	},
3166 
3167 	/**
3168 	 * Return a new Gregorian date instance that represents the first instance of the 
3169 	 * given day of the week on or after the current date. The day of the week is encoded
3170 	 * as a number where 0 = Sunday, 1 = Monday, etc.
3171 	 * 
3172 	 * @param {number} dow the day of the week on or after the current date that is being sought
3173 	 * @return {IDate} the date being sought
3174 	 */
3175 	onOrAfter: function (dow) {
3176 		return new this.constructor({
3177 			rd: this.rd.onOrAfter(dow, this.offset),
3178 			timezone: this.timezone
3179 		});
3180 	},
3181 	
3182 	/**
3183 	 * Return a Javascript Date object that is equivalent to this date
3184 	 * object.
3185 	 * 
3186 	 * @return {Date|undefined} a javascript Date object
3187 	 */
3188 	getJSDate: function() {
3189 		var unix = this.rd.getTimeExtended();
3190 		return isNaN(unix) ? undefined : new Date(unix); 
3191 	},
3192 	
3193 	/**
3194 	 * Return the Rata Die (fixed day) number of this date.
3195 	 * 
3196 	 * @protected
3197 	 * @return {number} the rd date as a number
3198 	 */
3199 	getRataDie: function() {
3200 		return this.rd.getRataDie();
3201 	},
3202 	
3203 	/**
3204 	 * Set the date components of this instance based on the given rd.
3205 	 * @protected
3206 	 * @param {number} rd the rata die date to set
3207 	 */
3208 	setRd: function (rd) {
3209 		this.rd = this.newRd({
3210 			rd: rd,
3211 			cal: this.cal
3212 		});
3213 		this._calcDateComponents();
3214 	},
3215 	
3216 	/**
3217 	 * Return the Julian Day equivalent to this calendar date as a number.
3218 	 * 
3219 	 * @return {number} the julian date equivalent of this date
3220 	 */
3221 	getJulianDay: function() {
3222 		return this.rd.getJulianDay();
3223 	},
3224 	
3225 	/**
3226 	 * Set the date of this instance using a Julian Day.
3227 	 * @param {number|JulianDay} date the Julian Day to use to set this date
3228 	 */
3229 	setJulianDay: function (date) {
3230 		this.rd = this.newRd({
3231 			julianday: (typeof(date) === 'object') ? date.getDate() : date,
3232 			cal: this.cal
3233 		});
3234 		this._calcDateComponents();
3235 	},
3236 
3237 	/**
3238 	 * Return the time zone associated with this date, or 
3239 	 * undefined if none was specified in the constructor.
3240 	 * 
3241 	 * @return {string|undefined} the name of the time zone for this date instance
3242 	 */
3243 	getTimeZone: function() {
3244 		return this.timezone || "local";
3245 	},
3246 	
3247 	/**
3248 	 * Set the time zone associated with this date.
3249 	 * @param {string=} tzName the name of the time zone to set into this date instance,
3250 	 * or "undefined" to unset the time zone 
3251 	 */
3252 	setTimeZone: function (tzName) {
3253 		if (!tzName || tzName === "") {
3254 			// same as undefining it
3255 			this.timezone = undefined;
3256 			this.tz = undefined;
3257 		} else if (typeof(tzName) === 'string') {
3258 			this.timezone = tzName;
3259 			this.tz = undefined;
3260 			// assuming the same UTC time, but a new time zone, now we have to 
3261 			// recalculate what the date components are
3262 			this._calcDateComponents();
3263 		}
3264 	},
3265 	
3266 	/**
3267 	 * Return the rd number of the first Sunday of the given ISO year.
3268 	 * @protected
3269 	 * @param {number} year the year for which the first Sunday is being sought
3270 	 * @return {number} the rd of the first Sunday of the ISO year
3271 	 */
3272 	firstSunday: function (year) {
3273 		var firstDay = this.newRd({
3274 			year: year,
3275 			month: 1,
3276 			day: 1,
3277 			hour: 0,
3278 			minute: 0,
3279 			second: 0,
3280 			millisecond: 0,
3281 			cal: this.cal
3282 		});
3283 		var firstThu = this.newRd({
3284 			rd: firstDay.onOrAfter(4),
3285 			cal: this.cal
3286 		});
3287 		return firstThu.before(0);
3288 	},
3289 	
3290 	/**
3291 	 * Return the ISO 8601 week number in the current year for the current date. The week
3292 	 * number ranges from 0 to 55, as some years have 55 weeks assigned to them in some
3293 	 * calendars.
3294 	 * 
3295 	 * @return {number} the week number for the current date
3296 	 */
3297 	getWeekOfYear: function() {
3298 		var rd = Math.floor(this.rd.getRataDie());
3299 		var year = this._calcYear(rd + this.offset);
3300 		var yearStart = this.firstSunday(year);
3301 		var nextYear;
3302 		
3303 		// if we have a January date, it may be in this ISO year or the previous year
3304 		if (rd < yearStart) {
3305 			yearStart = this.firstSunday(year-1);
3306 		} else {
3307 			// if we have a late December date, it may be in this ISO year, or the next year
3308 			nextYear = this.firstSunday(year+1);
3309 			if (rd >= nextYear) {
3310 				yearStart = nextYear;
3311 			}
3312 		}
3313 		
3314 		return Math.floor((rd-yearStart)/7) + 1;
3315 	},
3316 	
3317 	/**
3318 	 * Return the ordinal number of the week within the month. The first week of a month is
3319 	 * the first one that contains 4 or more days in that month. If any days precede this
3320 	 * first week, they are marked as being in week 0. This function returns values from 0
3321 	 * through 6.<p>
3322 	 * 
3323 	 * The locale is a required parameter because different locales that use the same 
3324 	 * Gregorian calendar consider different days of the week to be the beginning of
3325 	 * the week. This can affect the week of the month in which some days are located.
3326 	 * 
3327 	 * @param {Locale|string} locale the locale or locale spec to use when figuring out 
3328 	 * the first day of the week
3329 	 * @return {number} the ordinal number of the week within the current month
3330 	 */
3331 	getWeekOfMonth: function(locale) {
3332 		var li = new LocaleInfo(locale);
3333 		
3334 		var first = this.newRd({
3335 			year: this._calcYear(this.rd.getRataDie()+this.offset),
3336 			month: this.getMonths(),
3337 			day: 1,
3338 			hour: 0,
3339 			minute: 0,
3340 			second: 0,
3341 			millisecond: 0,
3342 			cal: this.cal
3343 		});
3344 		var weekStart = first.onOrAfter(li.getFirstDayOfWeek());
3345 		
3346 		if (weekStart - first.getRataDie() > 3) {
3347 			// if the first week has 4 or more days in it of the current month, then consider
3348 			// that week 1. Otherwise, it is week 0. To make it week 1, move the week start
3349 			// one week earlier.
3350 			weekStart -= 7;
3351 		}
3352 		return Math.floor((this.rd.getRataDie() - weekStart) / 7) + 1;
3353 	}
3354 };
3355 
3356 
3357 /*< MathUtils.js */
3358 /*
3359  * MathUtils.js - Misc math utility routines
3360  * 
3361  * Copyright © 2013-2015, JEDLSoft
3362  *
3363  * Licensed under the Apache License, Version 2.0 (the "License");
3364  * you may not use this file except in compliance with the License.
3365  * You may obtain a copy of the License at
3366  *
3367  *     http://www.apache.org/licenses/LICENSE-2.0
3368  *
3369  * Unless required by applicable law or agreed to in writing, software
3370  * distributed under the License is distributed on an "AS IS" BASIS,
3371  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3372  *
3373  * See the License for the specific language governing permissions and
3374  * limitations under the License.
3375  */
3376 
3377 var MathUtils = {};
3378 
3379 /**
3380  * Return the sign of the given number. If the sign is negative, this function
3381  * returns -1. If the sign is positive or zero, this function returns 1.
3382  * @static
3383  * @param {number} num the number to test
3384  * @return {number} -1 if the number is negative, and 1 otherwise
3385  */
3386 MathUtils.signum = function (num) {
3387 	var n = num;
3388 	if (typeof(num) === 'string') {
3389 		n = parseInt(num, 10);
3390 	} else if (typeof(num) !== 'number') {
3391 		return 1;
3392 	}
3393 	return (n < 0) ? -1 : 1;
3394 };
3395 
3396 /**
3397  * @static
3398  * @protected
3399  * @param {number} num number to round
3400  * @return {number} rounded number
3401  */
3402 MathUtils.floor = function (num) {
3403 	return Math.floor(num);
3404 };
3405 
3406 /**
3407  * @static
3408  * @protected
3409  * @param {number} num number to round
3410  * @return {number} rounded number
3411  */
3412 MathUtils.ceiling = function (num) {
3413 	return Math.ceil(num);
3414 };
3415 
3416 /**
3417  * @static
3418  * @protected
3419  * @param {number} num number to round
3420  * @return {number} rounded number
3421  */
3422 MathUtils.down = function (num) {
3423 	return (num < 0) ? Math.ceil(num) : Math.floor(num);
3424 };
3425 
3426 /**
3427  * @static
3428  * @protected
3429  * @param {number} num number to round
3430  * @return {number} rounded number
3431  */
3432 MathUtils.up = function (num) {
3433 	return (num < 0) ? Math.floor(num) : Math.ceil(num);
3434 };
3435 
3436 /**
3437  * @static
3438  * @protected
3439  * @param {number} num number to round
3440  * @return {number} rounded number
3441  */
3442 MathUtils.halfup = function (num) {
3443 	return (num < 0) ? Math.ceil(num - 0.5) : Math.floor(num + 0.5);
3444 };
3445 
3446 /**
3447  * @static
3448  * @protected
3449  * @param {number} num number to round
3450  * @return {number} rounded number
3451  */
3452 MathUtils.halfdown = function (num) {
3453 	return (num < 0) ? Math.floor(num + 0.5) : Math.ceil(num - 0.5);
3454 };
3455 
3456 /**
3457  * @static
3458  * @protected
3459  * @param {number} num number to round
3460  * @return {number} rounded number
3461  */
3462 MathUtils.halfeven = function (num) {
3463 	return (Math.floor(num) % 2 === 0) ? Math.ceil(num - 0.5) : Math.floor(num + 0.5);
3464 };
3465 
3466 /**
3467  * @static
3468  * @protected
3469  * @param {number} num number to round
3470  * @return {number} rounded number
3471  */
3472 MathUtils.halfodd = function (num) {
3473 	return (Math.floor(num) % 2 !== 0) ? Math.ceil(num - 0.5) : Math.floor(num + 0.5);
3474 };
3475 
3476 /**
3477  * Do a proper modulo function. The Javascript % operator will give the truncated
3478  * division algorithm, but for calendrical calculations, we need the Euclidean
3479  * division algorithm where the remainder of any division, whether the dividend
3480  * is negative or not, is always a positive number in the range [0, modulus).<p>
3481  * 
3482  * 
3483  * @static
3484  * @param {number} dividend the number being divided
3485  * @param {number} modulus the number dividing the dividend. This should always be a positive number.
3486  * @return the remainder of dividing the dividend by the modulus.  
3487  */
3488 MathUtils.mod = function (dividend, modulus) {
3489 	if (modulus == 0) {
3490 		return 0;
3491 	}
3492 	var x = dividend % modulus;
3493 	return (x < 0) ? x + modulus : x;
3494 };
3495 
3496 /**
3497  * Do a proper adjusted modulo function. The Javascript % operator will give the truncated
3498  * division algorithm, but for calendrical calculations, we need the Euclidean
3499  * division algorithm where the remainder of any division, whether the dividend
3500  * is negative or not, is always a positive number in the range (0, modulus]. The adjusted
3501  * modulo function differs from the regular modulo function in that when the remainder is
3502  * zero, the modulus should be returned instead.<p>
3503  * 
3504  * 
3505  * @static
3506  * @param {number} dividend the number being divided
3507  * @param {number} modulus the number dividing the dividend. This should always be a positive number.
3508  * @return the remainder of dividing the dividend by the modulus.  
3509  */
3510 MathUtils.amod = function (dividend, modulus) {
3511 	if (modulus == 0) {
3512 		return 0;
3513 	}
3514 	var x = dividend % modulus;
3515 	return (x <= 0) ? x + modulus : x;
3516 };
3517 
3518 
3519 
3520 /*< IString.js */
3521 /*
3522  * IString.js - ilib string subclass definition
3523  * 
3524  * Copyright © 2012-2015, JEDLSoft
3525  *
3526  * Licensed under the Apache License, Version 2.0 (the "License");
3527  * you may not use this file except in compliance with the License.
3528  * You may obtain a copy of the License at
3529  *
3530  *     http://www.apache.org/licenses/LICENSE-2.0
3531  *
3532  * Unless required by applicable law or agreed to in writing, software
3533  * distributed under the License is distributed on an "AS IS" BASIS,
3534  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3535  *
3536  * See the License for the specific language governing permissions and
3537  * limitations under the License.
3538  */
3539 
3540 // !depends ilib.js Utils.js Locale.js MathUtils.js
3541 
3542 // !data plurals
3543 
3544 
3545 /**
3546  * @class
3547  * Create a new ilib string instance. This string inherits from and
3548  * extends the Javascript String class. It can be
3549  * used almost anywhere that a normal Javascript string is used, though in
3550  * some instances you will need to call the {@link #toString} method when
3551  * a built-in Javascript string is needed. The formatting methods are 
3552  * methods that are not in the intrinsic String class and are most useful
3553  * when localizing strings in an app or web site in combination with 
3554  * the ResBundle class.<p>
3555  * 
3556  * This class is named IString ("ilib string") so as not to conflict with the 
3557  * built-in Javascript String class.
3558  * 
3559  * @constructor
3560  * @param {string|IString=} string initialize this instance with this string 
3561  */
3562 var IString = function (string) {
3563 	if (typeof(string) === 'object') {
3564 		if (string instanceof IString) {
3565 			this.str = string.str;	
3566 		} else {
3567 			this.str = string.toString();
3568 		}
3569 	} else if (typeof(string) === 'string') {
3570 		this.str = new String(string);
3571 	} else {
3572 		this.str = "";
3573 	}
3574 	this.length = this.str.length;
3575 	this.cpLength = -1;
3576 	this.localeSpec = ilib.getLocale();
3577 };
3578 
3579 /**
3580  * Return true if the given character is a Unicode surrogate character,
3581  * either high or low.
3582  * 
3583  * @private
3584  * @static
3585  * @param {string} ch character to check
3586  * @return {boolean} true if the character is a surrogate
3587  */
3588 IString._isSurrogate = function (ch) {
3589 	var n = ch.charCodeAt(0);
3590 	return ((n >= 0xDC00 && n <= 0xDFFF) || (n >= 0xD800 && n <= 0xDBFF));
3591 };
3592 
3593 /**
3594  * Convert a UCS-4 code point to a Javascript string. The codepoint can be any valid 
3595  * UCS-4 Unicode character, including supplementary characters. Standard Javascript
3596  * only supports supplementary characters using the UTF-16 encoding, which has 
3597  * values in the range 0x0000-0xFFFF. String.fromCharCode() will only
3598  * give you a string containing 16-bit characters, and will not properly convert 
3599  * the code point for a supplementary character (which has a value > 0xFFFF) into 
3600  * two UTF-16 surrogate characters. Instead, it will just just give you whatever
3601  * single character happens to be the same as your code point modulo 0x10000, which
3602  * is almost never what you want.<p> 
3603  * 
3604  * Similarly, that means if you use String.charCodeAt()
3605  * you will only retrieve a 16-bit value, which may possibly be a single
3606  * surrogate character that is part of a surrogate pair representing a character
3607  * in the supplementary plane. It will not give you a code point. Use 
3608  * IString.codePointAt() to access code points in a string, or use 
3609  * an iterator to walk through the code points in a string. 
3610  * 
3611  * @static
3612  * @param {number} codepoint UCS-4 code point to convert to a character
3613  * @return {string} a string containing the character represented by the codepoint
3614  */
3615 IString.fromCodePoint = function (codepoint) {
3616 	if (codepoint < 0x10000) {
3617 		return String.fromCharCode(codepoint);
3618 	} else {
3619 		var high = Math.floor(codepoint / 0x10000) - 1;
3620 		var low = codepoint & 0xFFFF;
3621 		
3622 		return String.fromCharCode(0xD800 | ((high & 0x000F) << 6) |  ((low & 0xFC00) >> 10)) +
3623 			String.fromCharCode(0xDC00 | (low & 0x3FF));
3624 	}
3625 };
3626 
3627 /**
3628  * Convert the character or the surrogate pair at the given
3629  * index into the intrinsic Javascript string to a Unicode 
3630  * UCS-4 code point.
3631  * 
3632  * @static
3633  * @param {string} str string to get the code point from
3634  * @param {number} index index into the string
3635  * @return {number} code point of the character at the
3636  * given index into the string
3637  */
3638 IString.toCodePoint = function(str, index) {
3639 	if (!str || str.length === 0) {
3640 		return -1;
3641 	}
3642 	var code = -1, high = str.charCodeAt(index);
3643 	if (high >= 0xD800 && high <= 0xDBFF) {
3644 		if (str.length > index+1) {
3645 			var low = str.charCodeAt(index+1);
3646 			if (low >= 0xDC00 && low <= 0xDFFF) {
3647 				code = (((high & 0x3C0) >> 6) + 1) << 16 |
3648 					(((high & 0x3F) << 10) | (low & 0x3FF));
3649 			}
3650 		}
3651 	} else {
3652 		code = high;
3653 	}
3654 	
3655 	return code;
3656 };
3657 
3658 /**
3659  * Load the plural the definitions of plurals for the locale.
3660  * @param {boolean=} sync
3661  * @param {Locale|string=} locale
3662  * @param {Object=} loadParams
3663  * @param {function(*)=} onLoad
3664  */
3665 IString.loadPlurals = function (sync, locale, loadParams, onLoad) {
3666 	var loc;
3667 	if (locale) {
3668 		loc = (typeof(locale) === 'string') ? new Locale(locale) : locale;
3669 	} else {
3670 		loc = new Locale(ilib.getLocale());
3671 	}
3672 	var spec = loc.getLanguage();
3673 	if (!ilib.data["plurals_" + spec]) {
3674 		Utils.loadData({
3675 			name: "plurals.json",
3676 			object: IString,
3677 			locale: loc,
3678 			sync: sync,
3679 			loadParams: loadParams,
3680 			callback: ilib.bind(this, function(plurals) {
3681 				if (!plurals) {
3682 					IString.cache[spec] = {};
3683 				}
3684 				ilib.data["plurals_" + spec] = plurals || {};
3685 				if (onLoad && typeof(onLoad) === 'function') {
3686 					onLoad(ilib.data["plurals_" + spec]);
3687 				}
3688 			})
3689 		});
3690 	} else {
3691 		if (onLoad && typeof(onLoad) === 'function') {
3692 			onLoad(ilib.data["plurals_" + spec]);
3693 		}
3694 	}
3695 };
3696 
3697 /**
3698  * @private
3699  * @static
3700  */
3701 IString._fncs = {
3702 	/**
3703 	 * @private
3704 	 * @param {Object} obj
3705 	 * @return {string|undefined}
3706 	 */
3707 	firstProp: function (obj) {
3708 		for (var p in obj) {
3709 			if (p && obj[p]) {
3710 				return p;
3711 			}
3712 		}
3713 		return undefined; // should never get here
3714 	},
3715 
3716 	/**
3717 	 * @private
3718 	 * @param {Object} obj
3719 	 * @return {string|undefined}
3720 	 */
3721 	firstPropRule: function (obj) {
3722 		if (Object.prototype.toString.call(obj) === '[object Array]') {
3723 			return "inrange";
3724 		} else if (Object.prototype.toString.call(obj) === '[object Object]') {
3725 			for (var p in obj) {
3726 				if (p && obj[p]) {
3727 					return p;
3728 				}
3729 			}
3730 
3731 		}
3732 		return undefined; // should never get here
3733 	},
3734 	
3735 	/**
3736 	 * @private
3737 	 * @param {Object} obj
3738 	 * @param {number|Object} n
3739 	 * @return {?}
3740 	 */
3741 	getValue: function (obj, n) {
3742 		if (typeof(obj) === 'object') {
3743 			var subrule = IString._fncs.firstPropRule(obj);
3744 			if (subrule === "inrange") {
3745 				return IString._fncs[subrule](obj, n);
3746 			}
3747 			return IString._fncs[subrule](obj[subrule], n);
3748 		} else if (typeof(obj) === 'string') {
3749 			if (typeof(n) === 'object'){
3750 				return n[obj];
3751 			}
3752 			return n;
3753 		} else {
3754 			return obj;
3755 		}
3756 	},
3757 	
3758 	/**
3759 	 * @private
3760 	 * @param {number|Object} n
3761 	 * @param {Array.<number|Array.<number>>|Object} range
3762 	 * @return {boolean}
3763 	 */
3764 	matchRangeContinuous: function(n, range) {
3765 		
3766 		for (var num in range) {
3767 			if (typeof(num) !== 'undefined' && typeof(range[num]) !== 'undefined') {
3768 				var obj = range[num];
3769 				if (typeof(obj) === 'number') {
3770 					if (n === range[num]) {
3771 						return true;
3772 					} else if (n >= range[0] && n <= range[1]) {
3773 						return true;
3774 					}
3775 				} else if (Object.prototype.toString.call(obj) === '[object Array]') {
3776 					if (n >= obj[0] && n <= obj[1]) {
3777 						return true;
3778 					}
3779 				}
3780 			}
3781 		}
3782 		return false;
3783 	},
3784 	
3785 	/**
3786 	 * @private
3787 	 * @param {*} number
3788 	 * @return {Object}
3789 	 */
3790 	calculateNumberDigits: function(number) {
3791 		var numberToString = number.toString();
3792 		var parts = [];
3793 		var numberDigits =  {};
3794 		var operandSymbol =  {};
3795 		var integerPart, decimalPartLength, decimalPart;
3796 
3797 		if (numberToString.indexOf('.') !== -1) { //decimal
3798 			parts = numberToString.split('.', 2);
3799 			numberDigits.integerPart = parseInt(parts[0], 10);
3800 			numberDigits.decimalPartLength = parts[1].length;
3801 			numberDigits.decimalPart = parseInt(parts[1], 10);
3802 
3803 			operandSymbol.n = parseFloat(number);
3804 			operandSymbol.i = numberDigits.integerPart;
3805 			operandSymbol.v = numberDigits.decimalPartLength;
3806 			operandSymbol.w = numberDigits.decimalPartLength;
3807 			operandSymbol.f = numberDigits.decimalPart;
3808 			operandSymbol.t = numberDigits.decimalPart;
3809 
3810 		} else {
3811 			numberDigits.integerPart = number;
3812 			numberDigits.decimalPartLength = 0;
3813 			numberDigits.decimalPart = 0;
3814 
3815 			operandSymbol.n = parseInt(number, 10);
3816 			operandSymbol.i = numberDigits.integerPart;
3817 			operandSymbol.v = 0;
3818 			operandSymbol.w = 0;
3819 			operandSymbol.f = 0;
3820 			operandSymbol.t = 0;
3821 
3822 		}
3823 		return operandSymbol
3824 	},
3825 
3826 	/**
3827 	 * @private
3828 	 * @param {number|Object} n
3829 	 * @param {Array.<number|Array.<number>>|Object} range
3830 	 * @return {boolean}
3831 	 */
3832 	matchRange: function(n, range) {
3833 		return IString._fncs.matchRangeContinuous(n, range);
3834 	},
3835 	
3836 	/**
3837 	 * @private
3838 	 * @param {Object} rule
3839 	 * @param {number} n
3840 	 * @return {boolean}
3841 	 */
3842 	is: function(rule, n) {
3843 		var left = IString._fncs.getValue(rule[0], n);
3844 		var right = IString._fncs.getValue(rule[1], n);
3845 		return left == right;
3846 	},
3847 	
3848 	/**
3849 	 * @private
3850 	 * @param {Object} rule
3851 	 * @param {number} n
3852 	 * @return {boolean}
3853 	 */
3854 	isnot: function(rule, n) {
3855 		return IString._fncs.getValue(rule[0], n) != IString._fncs.getValue(rule[1], n);
3856 	},
3857 	
3858 	/**
3859 	 * @private
3860 	 * @param {Object} rule
3861 	 * @param {number|Object} n
3862 	 * @return {boolean}
3863 	 */
3864 	inrange: function(rule, n) {
3865 		if (typeof(rule[0]) === 'number') {
3866 			if(typeof(n) === 'object') {
3867 				return IString._fncs.matchRange(n.n,rule);
3868 			}
3869 			return IString._fncs.matchRange(n,rule);	
3870 		} else if (typeof(rule[0]) === 'undefined') {
3871 			var subrule = IString._fncs.firstPropRule(rule);
3872 			return IString._fncs[subrule](rule[subrule], n);
3873 		} else {
3874 			return IString._fncs.matchRange(IString._fncs.getValue(rule[0], n), rule[1]);	
3875 		}
3876 	},
3877 	/**
3878 	 * @private
3879 	 * @param {Object} rule
3880 	 * @param {number} n
3881 	 * @return {boolean}
3882 	 */
3883 	notin: function(rule, n) {
3884 		return !IString._fncs.matchRange(IString._fncs.getValue(rule[0], n), rule[1]);
3885 	},
3886 	
3887 	/**
3888 	 * @private
3889 	 * @param {Object} rule
3890 	 * @param {number} n
3891 	 * @return {boolean}
3892 	 */
3893 	within: function(rule, n) {
3894 		return IString._fncs.matchRangeContinuous(IString._fncs.getValue(rule[0], n), rule[1]);		
3895 	},
3896 	
3897 	/**
3898 	 * @private
3899 	 * @param {Object} rule
3900 	 * @param {number} n
3901 	 * @return {number}
3902 	 */
3903 	mod: function(rule, n) {
3904 		return MathUtils.mod(IString._fncs.getValue(rule[0], n), IString._fncs.getValue(rule[1], n));
3905 	},
3906 	
3907 	/**
3908 	 * @private
3909 	 * @param {Object} rule
3910 	 * @param {number} n
3911 	 * @return {number}
3912 	 */
3913 	n: function(rule, n) {
3914 		return n;
3915 	},
3916 	
3917 	/**
3918 	 * @private
3919 	 * @param {Object} rule
3920 	 * @param {number|Object} n
3921 	 * @return {boolean}
3922 	 */
3923 	or: function(rule, n) {
3924 		var ruleLength = rule.length;
3925 		var result, i;
3926 		for (i=0; i < ruleLength; i++) {
3927 			result = IString._fncs.getValue(rule[i], n);
3928 			if (result) {
3929 				return true;
3930 			} 
3931 		}
3932 		return false;
3933 	},
3934 	/**
3935 	 * @private
3936 	 * @param {Object} rule
3937 	 * @param {number|Object} n
3938 	 * @return {boolean}
3939 	 */
3940 	and: function(rule, n) {
3941 		var ruleLength = rule.length;
3942 		var result, i;
3943 		for (i=0; i < ruleLength; i++) {
3944 			result= IString._fncs.getValue(rule[i], n);
3945 			if (!result) {
3946 				return false;
3947 			} 
3948 		}
3949 		return true;
3950 	},
3951 	/**
3952 	 * @private
3953 	 * @param {Object} rule
3954 	 * @param {number|Object} n
3955 	 * @return {boolean}
3956 	 */
3957 	eq: function(rule, n) {
3958 		var valueLeft = IString._fncs.getValue(rule[0], n);
3959 		var valueRight;
3960 
3961 		if (typeof(rule[0]) === 'string') {
3962 			if (typeof(n) === 'object'){
3963 				valueRight = n[rule[0]];
3964 				if (typeof(rule[1])=== 'number'){
3965 					valueRight = IString._fncs.getValue(rule[1], n);	
3966 				} else if (typeof(rule[1])=== 'object' && (IString._fncs.firstPropRule(rule[1]) === "inrange" )){
3967 					valueRight = IString._fncs.getValue(rule[1], n);	
3968 				}
3969 			}
3970 		} else {
3971 			if (IString._fncs.firstPropRule(rule[1]) === "inrange") { // mod
3972 				valueRight = IString._fncs.getValue(rule[1], valueLeft);
3973 			} else {
3974 				valueRight = IString._fncs.getValue(rule[1], n);
3975 			}
3976 		} 
3977 		if(typeof(valueRight) === 'boolean') {
3978 			return (valueRight ? true : false);
3979 		} else {
3980 			return (valueLeft == valueRight ? true :false);	
3981 		}
3982 	},
3983 	/**
3984 	 * @private
3985 	 * @param {Object} rule
3986 	 * @param {number|Object} n
3987 	 * @return {boolean}
3988 	 */
3989 	neq: function(rule, n) {
3990 		var valueLeft = IString._fncs.getValue(rule[0], n);
3991 		var valueRight;
3992 
3993 		if (typeof(rule[0]) === 'string') {
3994 			valueRight = n[rule[0]];
3995 			if (typeof(rule[1])=== 'number'){
3996 				valueRight = IString._fncs.getValue(rule[1], n);
3997 			}
3998 		} else {
3999 			if (IString._fncs.firstPropRule(rule[1]) === "inrange") { // mod
4000 				valueRight = IString._fncs.getValue(rule[1], valueLeft);
4001 			} else {
4002 				valueRight = IString._fncs.getValue(rule[1], n);	
4003 			}	
4004 		}
4005 
4006 		if(typeof(valueRight) === 'boolean') {//mod
4007 			return (valueRight? false : true);
4008 		} else {
4009 			return (valueLeft !== valueRight ? true :false);
4010 		}
4011 
4012 	}
4013 };
4014 
4015 IString.prototype = {
4016 	/**
4017 	 * Return the length of this string in characters. This function defers to the regular
4018 	 * Javascript string class in order to perform the length function. Please note that this
4019 	 * method is a real method, whereas the length property of Javascript strings is 
4020 	 * implemented by native code and appears as a property.<p>
4021 	 * 
4022 	 * Example:
4023 	 * 
4024 	 * <pre>
4025 	 * var str = new IString("this is a string");
4026 	 * console.log("String is " + str._length() + " characters long.");
4027 	 * </pre>
4028 	 * @private
4029 	 */
4030 	_length: function () {
4031 		return this.str.length;
4032 	},
4033 	
4034 	/**
4035 	 * Format this string instance as a message, replacing the parameters with 
4036 	 * the given values.<p>
4037 	 * 
4038 	 * The string can contain any text that a regular Javascript string can
4039 	 * contain. Replacement parameters have the syntax:
4040 	 * 
4041 	 * <pre>
4042 	 * {name}
4043 	 * </pre>
4044 	 * 
4045 	 * Where "name" can be any string surrounded by curly brackets. The value of 
4046 	 * "name" is taken from the parameters argument.<p>
4047 	 * 
4048 	 * Example:
4049 	 * 
4050 	 * <pre>
4051 	 * var str = new IString("There are {num} objects.");
4052 	 * console.log(str.format({
4053 	 *   num: 12
4054 	 * });
4055 	 * </pre>
4056 	 * 
4057 	 * Would give the output:
4058 	 * 
4059 	 * <pre>
4060 	 * There are 12 objects.
4061 	 * </pre>
4062 	 * 
4063 	 * If a property is missing from the parameter block, the replacement
4064 	 * parameter substring is left untouched in the string, and a different
4065 	 * set of parameters may be applied a second time. This way, different
4066 	 * parts of the code may format different parts of the message that they
4067 	 * happen to know about.<p>
4068 	 * 
4069 	 * Example:
4070 	 * 
4071 	 * <pre>
4072 	 * var str = new IString("There are {num} objects in the {container}.");
4073 	 * console.log(str.format({
4074 	 *   num: 12
4075 	 * });
4076 	 * </pre>
4077 	 * 
4078 	 * Would give the output:<p>
4079 	 * 
4080 	 * <pre>
4081 	 * There are 12 objects in the {container}.
4082 	 * </pre>
4083 	 * 
4084 	 * The result can then be formatted again with a different parameter block that
4085 	 * specifies a value for the container property.
4086 	 * 
4087 	 * @param params a Javascript object containing values for the replacement 
4088 	 * parameters in the current string
4089 	 * @return a new IString instance with as many replacement parameters filled
4090 	 * out as possible with real values.
4091 	 */
4092 	format: function (params) {
4093 		var formatted = this.str;
4094 		if (params) {
4095 			var regex;
4096 			for (var p in params) {
4097 				if (typeof(params[p]) !== 'undefined') {
4098 					regex = new RegExp("\{"+p+"\}", "g");
4099 					formatted = formatted.replace(regex, params[p]);
4100 				}
4101 			}
4102 		}
4103 		return formatted.toString();
4104 	},
4105 	
4106 	/**
4107 	 * Format a string as one of a choice of strings dependent on the value of
4108 	 * a particular argument index.<p>
4109 	 * 
4110 	 * The syntax of the choice string is as follows. The string contains a
4111 	 * series of choices separated by a vertical bar character "|". Each choice
4112 	 * has a value or range of values to match followed by a hash character "#"
4113 	 * followed by the string to use if the variable matches the criteria.<p>
4114 	 * 
4115 	 * Example string:
4116 	 * 
4117 	 * <pre>
4118 	 * var num = 2;
4119 	 * var str = new IString("0#There are no objects.|1#There is one object.|2#There are {number} objects.");
4120 	 * console.log(str.formatChoice(num, {
4121 	 *   number: num
4122 	 * }));
4123 	 * </pre>
4124 	 * 
4125 	 * Gives the output:
4126 	 * 
4127 	 * <pre>
4128 	 * "There are 2 objects."
4129 	 * </pre>
4130 	 * 
4131 	 * The strings to format may contain replacement variables that will be formatted
4132 	 * using the format() method above and the params argument as a source of values
4133 	 * to use while formatting those variables.<p>
4134 	 * 
4135 	 * If the criterion for a particular choice is empty, that choice will be used
4136 	 * as the default one for use when none of the other choice's criteria match.<p>
4137 	 * 
4138 	 * Example string:
4139 	 * 
4140 	 * <pre>
4141 	 * var num = 22;
4142 	 * var str = new IString("0#There are no objects.|1#There is one object.|#There are {number} objects.");
4143 	 * console.log(str.formatChoice(num, {
4144 	 *   number: num
4145 	 * }));
4146 	 * </pre>
4147 	 * 
4148 	 * Gives the output:
4149 	 * 
4150 	 * <pre>
4151 	 * "There are 22 objects."
4152 	 * </pre>
4153 	 * 
4154 	 * If multiple choice patterns can match a given argument index, the first one 
4155 	 * encountered in the string will be used. If no choice patterns match the 
4156 	 * argument index, then the default choice will be used. If there is no default
4157 	 * choice defined, then this method will return an empty string.<p>
4158 	 * 
4159 	 * <b>Special Syntax</b><p>
4160 	 * 
4161 	 * For any choice format string, all of the patterns in the string should be
4162 	 * of a single type: numeric, boolean, or string/regexp. The type of the 
4163 	 * patterns is determined by the type of the argument index parameter.<p>
4164 	 * 
4165 	 * If the argument index is numeric, then some special syntax can be used 
4166 	 * in the patterns to match numeric ranges.<p>
4167 	 * 
4168 	 * <ul>
4169 	 * <li><i>>x</i> - match any number that is greater than x 
4170 	 * <li><i>>=x</i> - match any number that is greater than or equal to x
4171 	 * <li><i><x</i> - match any number that is less than x
4172 	 * <li><i><=x</i> - match any number that is less than or equal to x
4173 	 * <li><i>start-end</i> - match any number in the range [start,end)
4174 	 * <li><i>zero</i> - match any number in the class "zero". (See below for
4175 	 * a description of number classes.)
4176 	 * <li><i>one</i> - match any number in the class "one"
4177 	 * <li><i>two</i> - match any number in the class "two"
4178 	 * <li><i>few</i> - match any number in the class "few"
4179 	 * <li><i>many</i> - match any number in the class "many"
4180 	 * </ul>
4181 	 * 
4182 	 * A number class defines a set of numbers that receive a particular syntax
4183 	 * in the strings. For example, in Slovenian, integers ending in the digit
4184 	 * "1" are in the "one" class, including 1, 21, 31, ... 101, 111, etc.
4185 	 * Similarly, integers ending in the digit "2" are in the "two" class. 
4186 	 * Integers ending in the digits "3" or "4" are in the "few" class, and
4187 	 * every other integer is handled by the default string.<p>
4188 	 * 
4189 	 * The definition of what numbers are included in a class is locale-dependent.
4190 	 * They are defined in the data file plurals.json. If your string is in a
4191 	 * different locale than the default for ilib, you should call the setLocale()
4192 	 * method of the string instance before calling this method.<p> 
4193 	 * 
4194 	 * <b>Other Pattern Types</b><p>
4195 	 * 
4196 	 * If the argument index is a boolean, the string values "true" and "false" 
4197 	 * may appear as the choice patterns.<p>
4198 	 * 
4199 	 * If the argument index is of type string, then the choice patterns may contain
4200 	 * regular expressions, or static strings as degenerate regexps.
4201 	 * 
4202 	 * @param {*} argIndex The index into the choice array of the current parameter
4203 	 * @param {Object} params The hash of parameter values that replace the replacement 
4204 	 * variables in the string
4205 	 * @throws "syntax error in choice format pattern: " if there is a syntax error
4206 	 * @return {string} the formatted string
4207 	 */
4208 	formatChoice: function(argIndex, params) {
4209 		var choices = this.str.split("|");
4210 		var type = typeof(argIndex);
4211 		var limits = [];
4212 		var strings = [];
4213 		var i;
4214 		var parts;
4215 		var limit;
4216 		var arg;
4217 		var result = undefined;
4218 		var defaultCase = "";
4219 		var	numberDigits = {};
4220 		var operandValue = {};
4221 	
4222 		if (this.str.length === 0) {
4223 			// nothing to do
4224 			return "";
4225 		}
4226 		
4227 		// first parse all the choices
4228 		for (i = 0; i < choices.length; i++) {		
4229 			parts = choices[i].split("#");		
4230 			if (parts.length > 2) {
4231 				limits[i] = parts[0];
4232 				parts = parts.shift();			
4233 				strings[i] = parts.join("#");
4234 			} else if (parts.length === 2) {
4235 				limits[i] = parts[0];
4236 				strings[i] = parts[1];
4237 			} else {
4238 				// syntax error
4239 				throw "syntax error in choice format pattern: " + choices[i];
4240 			}		
4241 		}
4242 		
4243 		// then apply the argument index
4244 		for (i = 0; i < limits.length; i++) {
4245 			if (limits[i].length === 0) {
4246 				// this is default case
4247 				defaultCase = new IString(strings[i]);			
4248 			} else {
4249 				switch (type) {
4250 					case 'number':
4251 						operandValue = IString._fncs.calculateNumberDigits(argIndex);
4252 											
4253 						if (limits[i].substring(0,2) === "<=") {						
4254 							limit = parseFloat(limits[i].substring(2));
4255 							if (operandValue.n <= limit) {
4256 								result = new IString(strings[i]);
4257 								i = limits.length;
4258 							}
4259 						} else if (limits[i].substring(0,2) === ">=") {						
4260 							limit = parseFloat(limits[i].substring(2));
4261 							if (operandValue.n >= limit) {
4262 								result = new IString(strings[i]);
4263 								i = limits.length;
4264 							}
4265 						} else if (limits[i].charAt(0) === "<") {						
4266 							limit = parseFloat(limits[i].substring(1));
4267 							if (operandValue.n < limit) {
4268 								result = new IString(strings[i]);
4269 								i = limits.length;
4270 							}
4271 						} else if (limits[i].charAt(0) === ">") {						
4272 							limit = parseFloat(limits[i].substring(1));
4273 							if (operandValue.n > limit) {
4274 								result = new IString(strings[i]);
4275 								i = limits.length;
4276 							}
4277 						} else {
4278 							this.locale = this.locale || new Locale(this.localeSpec);
4279 							switch (limits[i]) {
4280 								case "zero":
4281 								case "one":
4282 								case "two":
4283 								case "few":
4284 								case "many":
4285 									// CLDR locale-dependent number classes
4286 									var ruleset = ilib.data["plurals_" + this.locale.getLanguage()];
4287 									if (ruleset) {
4288 										var rule = ruleset[limits[i]];
4289 										if (IString._fncs.getValue(rule, operandValue)) {
4290 											result = new IString(strings[i]);
4291 											i = limits.length;
4292 										}
4293 									}
4294 									break;
4295 								default:
4296 									var dash = limits[i].indexOf("-");
4297 									if (dash !== -1) {							
4298 										// range
4299 										var start = limits[i].substring(0, dash);
4300 										var end = limits[i].substring(dash+1);							
4301 										if (operandValue.n >= parseInt(start, 10) && operandValue.n <= parseInt(end, 10)) {								
4302 											result = new IString(strings[i]);
4303 											i = limits.length;
4304 										}
4305 									} else if (operandValue.n === parseInt(limits[i], 10)) {							
4306 										// exact amount
4307 										result = new IString(strings[i]);
4308 										i = limits.length;
4309 									}
4310 									break;
4311 							}
4312 						}
4313 						break;
4314 					case 'boolean':					
4315 						if (limits[i] === "true" && argIndex === true) {						
4316 							result = new IString(strings[i]);
4317 							i = limits.length;
4318 						} else if (limits[i] === "false" && argIndex === false) {						
4319 							result = new IString(strings[i]);
4320 							i = limits.length;
4321 						}
4322 						break;
4323 					case 'string':					
4324 						var regexp = new RegExp(limits[i], "i");
4325 						if (regexp.test(argIndex)) {
4326 							result = new IString(strings[i]);
4327 							i = limits.length;
4328 						}
4329 						break;
4330 					case 'object':
4331 						throw "syntax error: fmtChoice parameter for the argument index cannot be an object";
4332 				}
4333 			}
4334 		}
4335 		
4336 		if (!result) {		
4337 			result = defaultCase || new IString("");
4338 		}
4339 		
4340 		result = result.format(params);
4341 		
4342 		return result.toString();
4343 	},
4344 	
4345 	// delegates
4346 	/**
4347 	 * Same as String.toString()
4348 	 * @return {string} this instance as regular Javascript string
4349 	 */
4350 	toString: function () {
4351 		return this.str.toString();
4352 	},
4353 	
4354 	/**
4355 	 * Same as String.valueOf()
4356 	 * @return {string} this instance as a regular Javascript string
4357 	 */
4358 	valueOf: function () {
4359 		return this.str.valueOf();
4360 	},
4361 	
4362 	/**
4363 	 * Same as String.charAt()
4364 	 * @param {number} index the index of the character being sought
4365 	 * @return {IString} the character at the given index
4366 	 */
4367 	charAt: function(index) {
4368 		return new IString(this.str.charAt(index));
4369 	},
4370 	
4371 	/**
4372 	 * Same as String.charCodeAt(). This only reports on 
4373 	 * 2-byte UCS-2 Unicode values, and does not take into
4374 	 * account supplementary characters encoded in UTF-16.
4375 	 * If you would like to take account of those characters,
4376 	 * use codePointAt() instead.
4377 	 * @param {number} index the index of the character being sought
4378 	 * @return {number} the character code of the character at the 
4379 	 * given index in the string 
4380 	 */
4381 	charCodeAt: function(index) {
4382 		return this.str.charCodeAt(index);
4383 	},
4384 	
4385 	/**
4386 	 * Same as String.concat()
4387 	 * @param {string} strings strings to concatenate to the current one
4388 	 * @return {IString} a concatenation of the given strings
4389 	 */
4390 	concat: function(strings) {
4391 		return new IString(this.str.concat(strings));
4392 	},
4393 	
4394 	/**
4395 	 * Same as String.indexOf()
4396 	 * @param {string} searchValue string to search for
4397 	 * @param {number} start index into the string to start searching, or
4398 	 * undefined to search the entire string
4399 	 * @return {number} index into the string of the string being sought,
4400 	 * or -1 if the string is not found 
4401 	 */
4402 	indexOf: function(searchValue, start) {
4403 		return this.str.indexOf(searchValue, start);
4404 	},
4405 	
4406 	/**
4407 	 * Same as String.lastIndexOf()
4408 	 * @param {string} searchValue string to search for
4409 	 * @param {number} start index into the string to start searching, or
4410 	 * undefined to search the entire string
4411 	 * @return {number} index into the string of the string being sought,
4412 	 * or -1 if the string is not found 
4413 	 */
4414 	lastIndexOf: function(searchValue, start) {
4415 		return this.str.lastIndexOf(searchValue, start);
4416 	},
4417 	
4418 	/**
4419 	 * Same as String.match()
4420 	 * @param {string} regexp the regular expression to match
4421 	 * @return {Array.<string>} an array of matches
4422 	 */
4423 	match: function(regexp) {
4424 		return this.str.match(regexp);
4425 	},
4426 	
4427 	/**
4428 	 * Same as String.replace()
4429 	 * @param {string} searchValue a regular expression to search for
4430 	 * @param {string} newValue the string to replace the matches with
4431 	 * @return {IString} a new string with all the matches replaced
4432 	 * with the new value
4433 	 */
4434 	replace: function(searchValue, newValue) {
4435 		return new IString(this.str.replace(searchValue, newValue));
4436 	},
4437 	
4438 	/**
4439 	 * Same as String.search()
4440 	 * @param {string} regexp the regular expression to search for
4441 	 * @return {number} position of the match, or -1 for no match
4442 	 */
4443 	search: function(regexp) {
4444 		return this.str.search(regexp);
4445 	},
4446 	
4447 	/**
4448 	 * Same as String.slice()
4449 	 * @param {number} start first character to include in the string
4450 	 * @param {number} end include all characters up to, but not including
4451 	 * the end character
4452 	 * @return {IString} a slice of the current string
4453 	 */
4454 	slice: function(start, end) {
4455 		return new IString(this.str.slice(start, end));
4456 	},
4457 	
4458 	/**
4459 	 * Same as String.split()
4460 	 * @param {string} separator regular expression to match to find
4461 	 * separations between the parts of the text
4462 	 * @param {number} limit maximum number of items in the final 
4463 	 * output array. Any items beyond that limit will be ignored.
4464 	 * @return {Array.<string>} the parts of the current string split 
4465 	 * by the separator
4466 	 */
4467 	split: function(separator, limit) {
4468 		return this.str.split(separator, limit);
4469 	},
4470 	
4471 	/**
4472 	 * Same as String.substr()
4473 	 * @param {number} start the index of the character that should 
4474 	 * begin the returned substring
4475 	 * @param {number} length the number of characters to return after
4476 	 * the start character.
4477 	 * @return {IString} the requested substring 
4478 	 */
4479 	substr: function(start, length) {
4480 		var plat = ilib._getPlatform();
4481 		if (plat === "qt" || plat === "rhino" || plat === "trireme") {
4482 			// qt and rhino have a broken implementation of substr(), so
4483 			// work around it
4484 			if (typeof(length) === "undefined") {
4485 				length = this.str.length - start;
4486 			}
4487 		}
4488 		return new IString(this.str.substr(start, length));
4489 	},
4490 	
4491 	/**
4492 	 * Same as String.substring()
4493 	 * @param {number} from the index of the character that should 
4494 	 * begin the returned substring
4495 	 * @param {number} to the index where to stop the extraction. If
4496 	 * omitted, extracts the rest of the string
4497 	 * @return {IString} the requested substring 
4498 	 */
4499 	substring: function(from, to) {
4500 		return this.str.substring(from, to);
4501 	},
4502 	
4503 	/**
4504 	 * Same as String.toLowerCase(). Note that this method is
4505 	 * not locale-sensitive. 
4506 	 * @return {IString} a string with the first character
4507 	 * lower-cased
4508 	 */
4509 	toLowerCase: function() {
4510 		return this.str.toLowerCase();
4511 	},
4512 	
4513 	/**
4514 	 * Same as String.toUpperCase(). Note that this method is
4515 	 * not locale-sensitive. Use toLocaleUpperCase() instead
4516 	 * to get locale-sensitive behaviour. 
4517 	 * @return {IString} a string with the first character
4518 	 * upper-cased
4519 	 */
4520 	toUpperCase: function() {
4521 		return this.str.toUpperCase();
4522 	},
4523 	
4524 	/**
4525 	 * Convert the character or the surrogate pair at the given
4526 	 * index into the string to a Unicode UCS-4 code point.
4527 	 * @protected
4528 	 * @param {number} index index into the string
4529 	 * @return {number} code point of the character at the
4530 	 * given index into the string
4531 	 */
4532 	_toCodePoint: function (index) {
4533 		return IString.toCodePoint(this.str, index);
4534 	},
4535 	
4536 	/**
4537 	 * Call the callback with each character in the string one at 
4538 	 * a time, taking care to step through the surrogate pairs in 
4539 	 * the UTF-16 encoding properly.<p>
4540 	 * 
4541 	 * The standard Javascript String's charAt() method only
4542 	 * returns a particular 16-bit character in the 
4543 	 * UTF-16 encoding scheme.
4544 	 * If the index to charAt() is pointing to a low- or 
4545 	 * high-surrogate character,
4546 	 * it will return the surrogate character rather 
4547 	 * than the the character 
4548 	 * in the supplementary planes that the two surrogates together 
4549 	 * encode. This function will call the callback with the full
4550 	 * character, making sure to join two  
4551 	 * surrogates into one character in the supplementary planes
4552 	 * where necessary.<p>
4553 	 * 
4554 	 * @param {function(string)} callback a callback function to call with each
4555 	 * full character in the current string
4556 	 */
4557 	forEach: function(callback) {
4558 		if (typeof(callback) === 'function') {
4559 			var it = this.charIterator();
4560 			while (it.hasNext()) {
4561 				callback(it.next());
4562 			}
4563 		}
4564 	},
4565 
4566 	/**
4567 	 * Call the callback with each numeric code point in the string one at 
4568 	 * a time, taking care to step through the surrogate pairs in 
4569 	 * the UTF-16 encoding properly.<p>
4570 	 * 
4571 	 * The standard Javascript String's charCodeAt() method only
4572 	 * returns information about a particular 16-bit character in the 
4573 	 * UTF-16 encoding scheme.
4574 	 * If the index to charCodeAt() is pointing to a low- or 
4575 	 * high-surrogate character,
4576 	 * it will return the code point of the surrogate character rather 
4577 	 * than the code point of the character 
4578 	 * in the supplementary planes that the two surrogates together 
4579 	 * encode. This function will call the callback with the full
4580 	 * code point of each character, making sure to join two  
4581 	 * surrogates into one code point in the supplementary planes.<p>
4582 	 * 
4583 	 * @param {function(string)} callback a callback function to call with each
4584 	 * code point in the current string
4585 	 */
4586 	forEachCodePoint: function(callback) {
4587 		if (typeof(callback) === 'function') {
4588 			var it = this.iterator();
4589 			while (it.hasNext()) {
4590 				callback(it.next());
4591 			}
4592 		}
4593 	},
4594 
4595 	/**
4596 	 * Return an iterator that will step through all of the characters
4597 	 * in the string one at a time and return their code points, taking 
4598 	 * care to step through the surrogate pairs in UTF-16 encoding 
4599 	 * properly.<p>
4600 	 * 
4601 	 * The standard Javascript String's charCodeAt() method only
4602 	 * returns information about a particular 16-bit character in the 
4603 	 * UTF-16 encoding scheme.
4604 	 * If the index is pointing to a low- or high-surrogate character,
4605 	 * it will return a code point of the surrogate character rather 
4606 	 * than the code point of the character 
4607 	 * in the supplementary planes that the two surrogates together 
4608 	 * encode.<p>
4609 	 * 
4610 	 * The iterator instance returned has two methods, hasNext() which
4611 	 * returns true if the iterator has more code points to iterate through,
4612 	 * and next() which returns the next code point as a number.<p>
4613 	 * 
4614 	 * @return {Object} an iterator 
4615 	 * that iterates through all the code points in the string
4616 	 */
4617 	iterator: function() {
4618 		/**
4619 		 * @constructor
4620 		 */
4621 		function _iterator (istring) {
4622 			this.index = 0;
4623 			this.hasNext = function () {
4624 				return (this.index < istring.str.length);
4625 			};
4626 			this.next = function () {
4627 				if (this.index < istring.str.length) {
4628 					var num = istring._toCodePoint(this.index);
4629 					this.index += ((num > 0xFFFF) ? 2 : 1);
4630 				} else {
4631 					num = -1;
4632 				}
4633 				return num;
4634 			};
4635 		};
4636 		return new _iterator(this);
4637 	},
4638 
4639 	/**
4640 	 * Return an iterator that will step through all of the characters
4641 	 * in the string one at a time, taking 
4642 	 * care to step through the surrogate pairs in UTF-16 encoding 
4643 	 * properly.<p>
4644 	 * 
4645 	 * The standard Javascript String's charAt() method only
4646 	 * returns information about a particular 16-bit character in the 
4647 	 * UTF-16 encoding scheme.
4648 	 * If the index is pointing to a low- or high-surrogate character,
4649 	 * it will return that surrogate character rather 
4650 	 * than the surrogate pair which represents a character 
4651 	 * in the supplementary planes.<p>
4652 	 * 
4653 	 * The iterator instance returned has two methods, hasNext() which
4654 	 * returns true if the iterator has more characters to iterate through,
4655 	 * and next() which returns the next character.<p>
4656 	 * 
4657 	 * @return {Object} an iterator 
4658 	 * that iterates through all the characters in the string
4659 	 */
4660 	charIterator: function() {
4661 		/**
4662 		 * @constructor
4663 		 */
4664 		function _chiterator (istring) {
4665 			this.index = 0;
4666 			this.hasNext = function () {
4667 				return (this.index < istring.str.length);
4668 			};
4669 			this.next = function () {
4670 				var ch;
4671 				if (this.index < istring.str.length) {
4672 					ch = istring.str.charAt(this.index);
4673 					if (IString._isSurrogate(ch) && 
4674 							this.index+1 < istring.str.length && 
4675 							IString._isSurrogate(istring.str.charAt(this.index+1))) {
4676 						this.index++;
4677 						ch += istring.str.charAt(this.index);
4678 					}
4679 					this.index++;
4680 				}
4681 				return ch;
4682 			};
4683 		};
4684 		return new _chiterator(this);
4685 	},
4686 	
4687 	/**
4688 	 * Return the code point at the given index when the string is viewed 
4689 	 * as an array of code points. If the index is beyond the end of the
4690 	 * array of code points or if the index is negative, -1 is returned.
4691 	 * @param {number} index index of the code point 
4692 	 * @return {number} code point of the character at the given index into
4693 	 * the string
4694 	 */
4695 	codePointAt: function (index) {
4696 		if (index < 0) {
4697 			return -1;
4698 		}
4699 		var count,
4700 			it = this.iterator(),
4701 			ch;
4702 		for (count = index; count >= 0 && it.hasNext(); count--) {
4703 			ch = it.next();
4704 		}
4705 		return (count < 0) ? ch : -1;
4706 	},
4707 	
4708 	/**
4709 	 * Set the locale to use when processing choice formats. The locale
4710 	 * affects how number classes are interpretted. In some cultures,
4711 	 * the limit "few" maps to "any integer that ends in the digits 2 to 9" and
4712 	 * in yet others, "few" maps to "any integer that ends in the digits
4713 	 * 3 or 4".
4714 	 * @param {Locale|string} locale locale to use when processing choice
4715 	 * formats with this string
4716 	 * @param {boolean=} sync [optional] whether to load the locale data synchronously 
4717 	 * or not
4718 	 * @param {Object=} loadParams [optional] parameters to pass to the loader function
4719 	 * @param {function(*)=} onLoad [optional] function to call when the loading is done
4720 	 */
4721 	setLocale: function (locale, sync, loadParams, onLoad) {
4722 		if (typeof(locale) === 'object') {
4723 			this.locale = locale;
4724 		} else {
4725 			this.localeSpec = locale;
4726 			this.locale = new Locale(locale);
4727 		}
4728 		
4729 		IString.loadPlurals(typeof(sync) !== 'undefined' ? sync : true, this.locale, loadParams, onLoad);
4730 	},
4731 
4732 	/**
4733 	 * Return the locale to use when processing choice formats. The locale
4734 	 * affects how number classes are interpretted. In some cultures,
4735 	 * the limit "few" maps to "any integer that ends in the digits 2 to 9" and
4736 	 * in yet others, "few" maps to "any integer that ends in the digits
4737 	 * 3 or 4".
4738 	 * @return {string} localespec to use when processing choice
4739 	 * formats with this string
4740 	 */
4741 	getLocale: function () {
4742 		return (this.locale ? this.locale.getSpec() : this.localeSpec) || ilib.getLocale();
4743 	},
4744 
4745 	/**
4746 	 * Return the number of code points in this string. This may be different
4747 	 * than the number of characters, as the UTF-16 encoding that Javascript
4748 	 * uses for its basis returns surrogate pairs separately. Two 2-byte 
4749 	 * surrogate characters together make up one character/code point in 
4750 	 * the supplementary character planes. If your string contains no
4751 	 * characters in the supplementary planes, this method will return the
4752 	 * same thing as the length() method.
4753 	 * @return {number} the number of code points in this string
4754 	 */
4755 	codePointLength: function () {
4756 		if (this.cpLength === -1) {
4757 			var it = this.iterator();
4758 			this.cpLength = 0;
4759 			while (it.hasNext()) { 
4760 				this.cpLength++;
4761 				it.next();
4762 			};
4763 		}
4764 		return this.cpLength;	
4765 	}
4766 };
4767 
4768 
4769 /*< Calendar.js */
4770 /*
4771  * Calendar.js - Represent a calendar object.
4772  * 
4773  * Copyright © 2012-2015, JEDLSoft
4774  *
4775  * Licensed under the Apache License, Version 2.0 (the "License");
4776  * you may not use this file except in compliance with the License.
4777  * You may obtain a copy of the License at
4778  *
4779  *     http://www.apache.org/licenses/LICENSE-2.0
4780  *
4781  * Unless required by applicable law or agreed to in writing, software
4782  * distributed under the License is distributed on an "AS IS" BASIS,
4783  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4784  *
4785  * See the License for the specific language governing permissions and
4786  * limitations under the License.
4787  */
4788 
4789 /**
4790  * @class
4791  * Superclass for all calendar subclasses that contains shared 
4792  * functionality. This class is never instantiated on its own. Instead,
4793  * you should use the {@link CalendarFactory} function to manufacture a new
4794  * instance of a subclass of Calendar. 
4795  * 
4796  * @private
4797  * @constructor
4798  */
4799 var Calendar = function() {
4800 };
4801 
4802 /* place for the subclasses to put their constructors so that the factory method
4803  * can find them. Do this to add your calendar after it's defined: 
4804  * Calendar._constructors["mytype"] = Calendar.MyTypeConstructor;
4805  */
4806 Calendar._constructors = {};
4807 
4808 Calendar.prototype = {
4809 	/**
4810 	 * Return the type of this calendar.
4811 	 * 
4812 	 * @return {string} the name of the type of this calendar 
4813 	 */
4814 	getType: function() {
4815 		throw "Cannot call methods of abstract class Calendar";
4816 	},
4817 	
4818 	/**
4819 	 * Return the number of months in the given year. The number of months in a year varies
4820 	 * for some luni-solar calendars because in some years, an extra month is needed to extend the 
4821 	 * days in a year to an entire solar year. The month is represented as a 1-based number
4822 	 * where 1=first month, 2=second month, etc.
4823 	 * 
4824 	 * @param {number} year a year for which the number of months is sought
4825 	 * @return {number} The number of months in the given year
4826 	 */
4827 	getNumMonths: function(year) {
4828 		throw "Cannot call methods of abstract class Calendar";
4829 	},
4830 	
4831 	/**
4832 	 * Return the number of days in a particular month in a particular year. This function
4833 	 * can return a different number for a month depending on the year because of things
4834 	 * like leap years.
4835 	 * 
4836 	 * @param {number} month the month for which the length is sought
4837 	 * @param {number} year the year within which that month can be found
4838 	 * @return {number} the number of days within the given month in the given year
4839 	 */
4840 	getMonLength: function(month, year) {
4841 		throw "Cannot call methods of abstract class Calendar";
4842 	},
4843 	
4844 	/**
4845 	 * Return true if the given year is a leap year in this calendar.
4846 	 * The year parameter may be given as a number.
4847 	 * 
4848 	 * @param {number} year the year for which the leap year information is being sought
4849 	 * @return {boolean} true if the given year is a leap year
4850 	 */
4851 	isLeapYear: function(year) {
4852 		throw "Cannot call methods of abstract class Calendar";
4853 	}
4854 };
4855 
4856 
4857 /*< CalendarFactory.js */
4858 /*
4859  * CalendarFactory.js - Constructs new instances of the right subclass of Calendar
4860  * 
4861  * Copyright © 2015, JEDLSoft
4862  *
4863  * Licensed under the Apache License, Version 2.0 (the "License");
4864  * you may not use this file except in compliance with the License.
4865  * You may obtain a copy of the License at
4866  *
4867  *     http://www.apache.org/licenses/LICENSE-2.0
4868  *
4869  * Unless required by applicable law or agreed to in writing, software
4870  * distributed under the License is distributed on an "AS IS" BASIS,
4871  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4872  *
4873  * See the License for the specific language governing permissions and
4874  * limitations under the License.
4875  */
4876 
4877 /* !depends
4878 ilib.js
4879 Locale.js
4880 LocaleInfo.js
4881 Calendar.js
4882 */
4883 
4884 
4885 /**
4886  * Factory method to create a new instance of a calendar subclass.<p>
4887  * 
4888  * The options parameter can be an object that contains the following
4889  * properties:
4890  * 
4891  * <ul>
4892  * <li><i>type</i> - specify the type of the calendar desired. The
4893  * list of valid values changes depending on which calendars are 
4894  * defined. When assembling your iliball.js, include those calendars 
4895  * you wish to use in your program or web page, and they will register 
4896  * themselves with this factory method. The "official", "gregorian",
4897  * and "julian" calendars are all included by default, as they are the
4898  * standard calendars for much of the world.
4899  * <li><i>locale</i> - some calendars vary depending on the locale.
4900  * For example, the "official" calendar transitions from a Julian-style
4901  * calendar to a Gregorian-style calendar on a different date for
4902  * each country, as the governments of those countries decided to
4903  * adopt the Gregorian calendar at different times.
4904  *  
4905  * <li><i>onLoad</i> - a callback function to call when the calendar object is fully 
4906  * loaded. When the onLoad option is given, the calendar factory will attempt to
4907  * load any missing locale data using the ilib loader callback.
4908  * When the constructor is done (even if the data is already preassembled), the 
4909  * onLoad function is called with the current instance as a parameter, so this
4910  * callback can be used with preassembled or dynamic loading or a mix of the two.
4911  * 
4912  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
4913  * asynchronously. If this option is given as "false", then the "onLoad"
4914  * callback must be given, as the instance returned from this constructor will
4915  * not be usable for a while.
4916  *  
4917  * <li><i>loadParams</i> - an object containing parameters to pass to the 
4918  * loader callback function when locale data is missing. The parameters are not
4919  * interpretted or modified in any way. They are simply passed along. The object 
4920  * may contain any property/value pairs as long as the calling code is in
4921  * agreement with the loader callback function as to what those parameters mean.
4922  * </ul>
4923  * 
4924  * If a locale is specified, but no type, then the calendar that is default for
4925  * the locale will be instantiated and returned. If neither the type nor
4926  * the locale are specified, then the calendar for the default locale will
4927  * be used. 
4928  * 
4929  * @static
4930  * @param {Object=} options options controlling the construction of this instance, or
4931  * undefined to use the default options
4932  * @return {Calendar} an instance of a calendar object of the appropriate type
4933  */
4934 var CalendarFactory = function (options) {
4935 	var locale,
4936 		type,
4937 		sync = true,
4938 		instance;
4939 
4940 	if (options) {
4941 		if (options.locale) {
4942 			locale = (typeof(options.locale) === 'string') ? new Locale(options.locale) : options.locale;
4943 		}
4944 		
4945 		type = options.type || options.calendar;
4946 		
4947 		if (typeof(options.sync) === 'boolean') {
4948 			sync = options.sync;
4949 		}
4950 	}
4951 	
4952 	if (!locale) {
4953 		locale = new Locale();	// default locale
4954 	}
4955 	
4956 	if (!type) {
4957 		new LocaleInfo(locale, {
4958 			sync: sync,
4959 			loadParams: options && options.loadParams,
4960 			onLoad: ilib.bind(this, function(info) {
4961 				type = info.getCalendar();
4962 				
4963 				instance = CalendarFactory._init(type, options);
4964 				
4965 				if (options && typeof(options.onLoad) === 'function') {
4966 					options.onLoad(instance);
4967 				}
4968 			})
4969 		});
4970 	} else {
4971 		instance = CalendarFactory._init(type, options);
4972 	}
4973 	
4974 	return instance;
4975 };
4976 
4977 /**
4978  * Map calendar names to classes to initialize in the dynamic code model.
4979  * TODO: Need to figure out some way that this doesn't have to be updated by hand.
4980  * @private
4981  */
4982 CalendarFactory._dynMap = {
4983 	"coptic":       "Coptic",
4984 	"ethiopic":     "Ethiopic",
4985 	"gregorian":    "Gregorian",
4986 	"han":          "Han",
4987 	"hebrew":       "Hebrew",
4988 	"islamic":      "Islamic",
4989 	"julian":       "Julian",
4990 	"persian":      "Persian",
4991 	"persian-algo": "PersianAlgo",
4992 	"thaisolar":    "ThaiSolar"
4993 };
4994 
4995 /**
4996  * Dynamically load the code for a calendar and calendar class if necessary.
4997  * @protected
4998  */
4999 CalendarFactory._dynLoadCalendar = function (name) {
5000 	if (!Calendar._constructors[name]) {
5001 		var entry = CalendarFactory._dynMap[name];
5002 		if (entry) {
5003 			Calendar._constructors[name] = require("./" + entry + "Cal.js");
5004 		}
5005 	}
5006 	return Calendar._constructors[name];
5007 };
5008 
5009 /** @private */
5010 CalendarFactory._init = function(type, options) {
5011 	var cons;
5012 	
5013 	if (ilib.isDynCode()) {
5014 		CalendarFactory._dynLoadCalendar(type);
5015 	}
5016 	
5017 	cons = Calendar._constructors[type];
5018 	
5019 	// pass the same options through to the constructor so the subclass
5020 	// has the ability to do something with if it needs to
5021 	return cons && new cons(options);
5022 };
5023 
5024 /**
5025  * Return an array of known calendar types that the factory method can instantiate.
5026  * 
5027  * @return {Array.<string>} an array of calendar types
5028  */
5029 CalendarFactory.getCalendars = function () {
5030 	var arr = [],
5031 		c;
5032 	
5033 	if (ilib.isDynCode()) {
5034 		for (c in CalendarFactory._dynMap) {
5035 			CalendarFactory._dynLoadCalendar(c);
5036 		}
5037 	}
5038 	
5039 	for (c in Calendar._constructors) {
5040 		if (c && Calendar._constructors[c]) {
5041 			arr.push(c); // code like a pirate
5042 		}
5043 	}
5044 	
5045 	return arr;
5046 };
5047 
5048 
5049 /*< GregorianCal.js */
5050 /*
5051  * gregorian.js - Represent a Gregorian calendar object.
5052  * 
5053  * Copyright © 2012-2015, JEDLSoft
5054  *
5055  * Licensed under the Apache License, Version 2.0 (the "License");
5056  * you may not use this file except in compliance with the License.
5057  * You may obtain a copy of the License at
5058  *
5059  *     http://www.apache.org/licenses/LICENSE-2.0
5060  *
5061  * Unless required by applicable law or agreed to in writing, software
5062  * distributed under the License is distributed on an "AS IS" BASIS,
5063  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
5064  *
5065  * See the License for the specific language governing permissions and
5066  * limitations under the License.
5067  */
5068 
5069 
5070 /* !depends ilib.js Calendar.js Utils.js MathUtils.js */
5071 
5072 
5073 /**
5074  * @class
5075  * Construct a new Gregorian calendar object. This class encodes information about
5076  * a Gregorian calendar.<p>
5077  * 
5078  * 
5079  * @constructor
5080  * @param {{noinstance:boolean}=} options
5081  * @extends Calendar
5082  */
5083 var GregorianCal = function(options) {
5084 	if (!options || !options.noinstance) {
5085 		this.type = "gregorian";
5086 	}
5087 };
5088 
5089 /**
5090  * the lengths of each month 
5091  * @private
5092  * @const
5093  * @type Array.<number> 
5094  */
5095 GregorianCal.monthLengths = [
5096 	31,  /* Jan */
5097 	28,  /* Feb */
5098 	31,  /* Mar */
5099 	30,  /* Apr */
5100 	31,  /* May */
5101 	30,  /* Jun */
5102 	31,  /* Jul */
5103 	31,  /* Aug */
5104 	30,  /* Sep */
5105 	31,  /* Oct */
5106 	30,  /* Nov */
5107 	31   /* Dec */
5108 ];
5109 
5110 /**
5111  * Return the number of months in the given year. The number of months in a year varies
5112  * for some luni-solar calendars because in some years, an extra month is needed to extend the 
5113  * days in a year to an entire solar year. The month is represented as a 1-based number
5114  * where 1=first month, 2=second month, etc.
5115  * 
5116  * @param {number} year a year for which the number of months is sought
5117  * @return {number} The number of months in the given year
5118  */
5119 GregorianCal.prototype.getNumMonths = function(year) {
5120 	return 12;
5121 };
5122 
5123 /**
5124  * Return the number of days in a particular month in a particular year. This function
5125  * can return a different number for a month depending on the year because of things
5126  * like leap years.
5127  * 
5128  * @param {number} month the month for which the length is sought
5129  * @param {number} year the year within which that month can be found
5130  * @return {number} the number of days within the given month in the given year
5131  */
5132 GregorianCal.prototype.getMonLength = function(month, year) {
5133 	if (month !== 2 || !this.isLeapYear(year)) {
5134 		return GregorianCal.monthLengths[month-1];
5135 	} else {
5136 		return 29;
5137 	}
5138 };
5139 
5140 /**
5141  * Return true if the given year is a leap year in the Gregorian calendar.
5142  * The year parameter may be given as a number, or as a GregDate object.
5143  * @param {number|GregorianDate} year the year for which the leap year information is being sought
5144  * @return {boolean} true if the given year is a leap year
5145  */
5146 GregorianCal.prototype.isLeapYear = function(year) {
5147 	var y = (typeof(year) === 'number' ? year : year.getYears());
5148 	var centuries = MathUtils.mod(y, 400);
5149 	return (MathUtils.mod(y, 4) === 0 && centuries !== 100 && centuries !== 200 && centuries !== 300);
5150 };
5151 
5152 /**
5153  * Return the type of this calendar.
5154  * 
5155  * @return {string} the name of the type of this calendar 
5156  */
5157 GregorianCal.prototype.getType = function() {
5158 	return this.type;
5159 };
5160 
5161 /**
5162  * Return a date instance for this calendar type using the given
5163  * options.
5164  * @param {Object} options options controlling the construction of 
5165  * the date instance
5166  * @return {IDate} a date appropriate for this calendar type
5167  * @deprecated Since 11.0.5. Use DateFactory({calendar: cal.getType(), ...}) instead
5168  */
5169 GregorianCal.prototype.newDateInstance = function (options) {
5170 		return new GregorianDate(options);
5171 };
5172 
5173 /* register this calendar for the factory method */
5174 Calendar._constructors["gregorian"] = GregorianCal;
5175 
5176 
5177 /*< JulianDay.js */
5178 /*
5179  * JulianDay.js - A Julian Day object.
5180  * 
5181  * Copyright © 2012-2015, JEDLSoft
5182  *
5183  * Licensed under the Apache License, Version 2.0 (the "License");
5184  * you may not use this file except in compliance with the License.
5185  * You may obtain a copy of the License at
5186  *
5187  *     http://www.apache.org/licenses/LICENSE-2.0
5188  *
5189  * Unless required by applicable law or agreed to in writing, software
5190  * distributed under the License is distributed on an "AS IS" BASIS,
5191  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
5192  *
5193  * See the License for the specific language governing permissions and
5194  * limitations under the License.
5195  */
5196 
5197 /**
5198  * @class
5199  * A Julian Day class. A Julian Day is a date based on the Julian Day count
5200  * of time invented by Joseph Scaliger in 1583 for use with astronomical calculations. 
5201  * Do not confuse it with a date in the Julian calendar, which it has very
5202  * little in common with. The naming is unfortunately close, and comes from history.<p>
5203  * 
5204  * 
5205  * @constructor
5206  * @param {number} num the Julian Day expressed as a floating point number 
5207  */
5208 var JulianDay = function(num) {
5209 	this.jd = num;
5210 	this.days = Math.floor(this.jd);
5211 	this.frac = num - this.days;
5212 };
5213 
5214 JulianDay.prototype = {
5215 	/**
5216 	 * Return the integral portion of this Julian Day instance. This corresponds to
5217 	 * the number of days since the beginning of the epoch.
5218 	 * 
5219 	 * @return {number} the integral portion of this Julian Day
5220 	 */
5221 	getDays: function() {
5222 		return this.days;
5223 	},
5224 	
5225 	/**
5226 	 * Set the date of this Julian Day instance.
5227 	 * 
5228 	 * @param {number} days the julian date expressed as a floating point number
5229 	 */
5230 	setDays: function(days) {
5231 		this.days = Math.floor(days);
5232 		this.jd = this.days + this.frac;
5233 	},
5234 	
5235 	/**
5236 	 * Return the fractional portion of this Julian Day instance. This portion 
5237 	 * corresponds to the time of day for the instance.
5238 	 */
5239 	getDayFraction: function() {
5240 		return this.frac;
5241 	},
5242 	
5243 	/**
5244 	 * Set the fractional part of the Julian Day. The fractional part represents
5245 	 * the portion of a fully day. Julian dates start at noon, and proceed until
5246 	 * noon of the next day. That would mean midnight is represented as a fractional
5247 	 * part of 0.5.
5248 	 * 
5249 	 * @param {number} fraction The fractional part of the Julian date
5250 	 */
5251 	setDayFraction: function(fraction) {
5252 		var t = Math.floor(fraction);
5253 		this.frac = fraction - t;
5254 		this.jd = this.days + this.frac;
5255 	},
5256 	
5257 	/** 
5258 	 * Return the Julian Day expressed as a floating point number.
5259 	 * @return {number} the Julian Day as a number
5260 	 */
5261 	getDate: function () {
5262 		return this.jd;
5263 	},
5264 	
5265 	/**
5266 	 * Set the date of this Julian Day instance.
5267 	 * 
5268 	 * @param {number} num the numeric Julian Day to set into this instance
5269 	 */
5270 	setDate: function (num) {
5271 		this.jd = num;
5272 	},
5273 	
5274 	/**
5275 	 * Add an offset to the current date instance. The offset should be expressed in
5276 	 * terms of Julian days. That is, each integral unit represents one day of time, and
5277 	 * fractional part represents a fraction of a regular 24-hour day.
5278 	 * 
5279 	 * @param {number} offset an amount to add (or subtract) to the current result instance.
5280 	 */
5281 	addDate: function(offset) {
5282 		if (typeof(offset) === 'number') {
5283 			this.jd += offset;
5284 			this.days = Math.floor(this.jd);
5285 			this.frac = this.jd - this.days;
5286 		}
5287 	}
5288 };
5289 
5290 
5291 
5292 /*< RataDie.js */
5293 /*
5294  * ratadie.js - Represent the RD date number in the calendar
5295  * 
5296  * Copyright © 2014-2015, JEDLSoft
5297  *
5298  * Licensed under the Apache License, Version 2.0 (the "License");
5299  * you may not use this file except in compliance with the License.
5300  * You may obtain a copy of the License at
5301  *
5302  *     http://www.apache.org/licenses/LICENSE-2.0
5303  *
5304  * Unless required by applicable law or agreed to in writing, software
5305  * distributed under the License is distributed on an "AS IS" BASIS,
5306  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
5307  *
5308  * See the License for the specific language governing permissions and
5309  * limitations under the License.
5310  */
5311 
5312 /* !depends 
5313 ilib.js
5314 JulianDay.js
5315 MathUtils.js
5316 JSUtils.js
5317 */
5318 
5319 
5320 /**
5321  * @class
5322  * Construct a new RD date number object. The constructor parameters can 
5323  * contain any of the following properties:
5324  * 
5325  * <ul>
5326  * <li><i>unixtime<i> - sets the time of this instance according to the given 
5327  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970.
5328  * 
5329  * <li><i>julianday</i> - sets the time of this instance according to the given
5330  * Julian Day instance or the Julian Day given as a float
5331  * 
5332  * <li><i>cycle</i> - any integer giving the number of 60-year cycle in which the date is located.
5333  * If the cycle is not given but the year is, it is assumed that the year parameter is a fictitious 
5334  * linear count of years since the beginning of the epoch, much like other calendars. This linear
5335  * count is never used. If both the cycle and year are given, the year is wrapped to the range 0 
5336  * to 60 and treated as if it were a year in the regular 60-year cycle.
5337  * 
5338  * <li><i>year</i> - any integer, including 0
5339  * 
5340  * <li><i>month</i> - 1 to 12, where 1 means January, 2 means February, etc.
5341  * 
5342  * <li><i>day</i> - 1 to 31
5343  * 
5344  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
5345  * is always done with an unambiguous 24 hour representation
5346  * 
5347  * <li><i>minute</i> - 0 to 59
5348  * 
5349  * <li><i>second</i> - 0 to 59
5350  * 
5351  * <li><i>millisecond</i> - 0 to 999
5352  * 
5353  * <li><i>parts</i> - 0 to 1079. Specify the halaqim parts of an hour. Either specify 
5354  * the parts or specify the minutes, seconds, and milliseconds, but not both. This is only used
5355  * in the Hebrew calendar. 
5356  * 
5357  * <li><i>minute</i> - 0 to 59
5358  * 
5359  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
5360  * </ul>
5361  *
5362  * If the constructor is called with another date instance instead of
5363  * a parameter block, the other instance acts as a parameter block and its
5364  * settings are copied into the current instance.<p>
5365  * 
5366  * If the constructor is called with no arguments at all or if none of the 
5367  * properties listed above are present, then the RD is calculate based on 
5368  * the current date at the time of instantiation. <p>
5369  * 
5370  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
5371  * specified in the params, it is assumed that they have the smallest possible
5372  * value in the range for the property (zero or one).<p>
5373  * 
5374  * 
5375  * @private
5376  * @constructor
5377  * @param {Object=} params parameters that govern the settings and behaviour of this RD date
5378  */
5379 var RataDie = function(params) {
5380 	if (params) {
5381 		if (typeof(params.date) !== 'undefined') {
5382 			// accept JS Date classes or strings
5383 			var date = params.date;
5384 			if (!(JSUtils.isDate(date))) {
5385 				date = new Date(date); // maybe a string initializer?
5386 			}
5387 			this._setTime(date.getTime());
5388 		} else if (typeof(params.unixtime) !== 'undefined') {
5389 			this._setTime(parseInt(params.unixtime, 10));
5390 		} else if (typeof(params.julianday) !== 'undefined') {
5391 			// JD time is defined to be UTC
5392 			this._setJulianDay(parseFloat(params.julianday));
5393 		} else if (params.year || params.month || params.day || params.hour ||
5394 				params.minute || params.second || params.millisecond || params.parts || params.cycle) {
5395 			this._setDateComponents(params);
5396 		} else if (typeof(params.rd) !== 'undefined') {
5397 			/**
5398 			 * @type {number} the Rata Die number of this date for this calendar type
5399 			 */
5400 			this.rd = (typeof(params.rd) === 'object' && params.rd instanceof RataDie) ? params.rd.rd : params.rd;
5401 		}
5402 	}
5403 	
5404 	if (typeof(this.rd) === 'undefined' || isNaN(this.rd)) {
5405 		var now = new Date();
5406 		this._setTime(now.getTime());
5407 	}
5408 };
5409 
5410 /**
5411  * @private
5412  * @const
5413  * @type {number}
5414  */
5415 RataDie.gregorianEpoch = 1721424.5;
5416 
5417 RataDie.prototype = {
5418 	/**
5419 	 * @protected
5420 	 * @type {number}
5421 	 * the difference between a zero Julian day and the zero Gregorian date. 
5422 	 */
5423 	epoch: RataDie.gregorianEpoch,
5424 	
5425 	/**
5426 	 * Set the RD of this instance according to the given unix time. Unix time is
5427 	 * the number of milliseconds since midnight on Jan 1, 1970.
5428 	 *
5429 	 * @protected
5430 	 * @param {number} millis the unix time to set this date to in milliseconds 
5431 	 */
5432 	_setTime: function(millis) {
5433 		// 2440587.5 is the julian day of midnight Jan 1, 1970, UTC (Gregorian)
5434 		this._setJulianDay(2440587.5 + millis / 86400000);
5435 	},
5436 
5437 	/**
5438 	 * Set the date of this instance using a Julian Day.
5439 	 * @protected
5440 	 * @param {number} date the Julian Day to use to set this date
5441 	 */
5442 	_setJulianDay: function (date) {
5443 		var jd = (typeof(date) === 'number') ? new JulianDay(date) : date;
5444 		// round to the nearest millisecond
5445 		this.rd = MathUtils.halfup((jd.getDate() - this.epoch) * 86400000) / 86400000;
5446 	},
5447 
5448 	/**
5449 	 * Return the rd number of the particular day of the week on or before the 
5450 	 * given rd. eg. The Sunday on or before the given rd.
5451 	 * @protected
5452 	 * @param {number} rd the rata die date of the reference date
5453 	 * @param {number} dayOfWeek the day of the week that is being sought relative 
5454 	 * to the current date
5455 	 * @return {number} the rd of the day of the week
5456 	 */
5457 	_onOrBefore: function(rd, dayOfWeek) {
5458 		return rd - MathUtils.mod(Math.floor(rd) - dayOfWeek - 2, 7);
5459 	},
5460 	
5461 	/**
5462 	 * Return the rd number of the particular day of the week on or before the current rd.
5463 	 * eg. The Sunday on or before the current rd. If the offset is given, the calculation
5464 	 * happens in wall time instead of UTC. UTC time may be a day before or day behind 
5465 	 * wall time, so it it would give the wrong day of the week if this calculation was
5466 	 * done in UTC time when the caller really wanted wall time. Even though the calculation
5467 	 * may be done in wall time, the return value is nonetheless always given in UTC.
5468 	 * @param {number} dayOfWeek the day of the week that is being sought relative 
5469 	 * to the current date
5470 	 * @param {number=} offset RD offset for the time zone. Zero is assumed if this param is
5471 	 * not given
5472 	 * @return {number} the rd of the day of the week
5473 	 */
5474 	onOrBefore: function(dayOfWeek, offset) {
5475 		offset = offset || 0;
5476 		return this._onOrBefore(this.rd + offset, dayOfWeek) - offset;
5477 	},
5478 	
5479 	/**
5480 	 * Return the rd number of the particular day of the week on or before the current rd.
5481 	 * eg. The Sunday on or before the current rd. If the offset is given, the calculation
5482 	 * happens in wall time instead of UTC. UTC time may be a day before or day behind 
5483 	 * wall time, so it it would give the wrong day of the week if this calculation was
5484 	 * done in UTC time when the caller really wanted wall time. Even though the calculation
5485 	 * may be done in wall time, the return value is nonetheless always given in UTC.
5486 	 * @param {number} dayOfWeek the day of the week that is being sought relative 
5487 	 * to the reference date
5488 	 * @param {number=} offset RD offset for the time zone. Zero is assumed if this param is
5489 	 * not given
5490 	 * @return {number} the day of the week
5491 	 */
5492 	onOrAfter: function(dayOfWeek, offset) {
5493 		offset = offset || 0;
5494 		return this._onOrBefore(this.rd+6+offset, dayOfWeek) - offset;
5495 	},
5496 	
5497 	/**
5498 	 * Return the rd number of the particular day of the week before the current rd.
5499 	 * eg. The Sunday before the current rd. If the offset is given, the calculation
5500 	 * happens in wall time instead of UTC. UTC time may be a day before or day behind 
5501 	 * wall time, so it it would give the wrong day of the week if this calculation was
5502 	 * done in UTC time when the caller really wanted wall time. Even though the calculation
5503 	 * may be done in wall time, the return value is nonetheless always given in UTC.
5504 	 * @param {number} dayOfWeek the day of the week that is being sought relative 
5505 	 * to the reference date
5506 	 * @param {number=} offset RD offset for the time zone. Zero is assumed if this param is
5507 	 * not given
5508 	 * @return {number} the day of the week
5509 	 */
5510 	before: function(dayOfWeek, offset) {
5511 		offset = offset || 0;
5512 		return this._onOrBefore(this.rd-1+offset, dayOfWeek) - offset;
5513 	},
5514 	
5515 	/**
5516 	 * Return the rd number of the particular day of the week after the current rd.
5517 	 * eg. The Sunday after the current rd. If the offset is given, the calculation
5518 	 * happens in wall time instead of UTC. UTC time may be a day before or day behind 
5519 	 * wall time, so it it would give the wrong day of the week if this calculation was
5520 	 * done in UTC time when the caller really wanted wall time. Even though the calculation
5521 	 * may be done in wall time, the return value is nonetheless always given in UTC.
5522 	 * @param {number} dayOfWeek the day of the week that is being sought relative 
5523 	 * to the reference date
5524 	 * @param {number=} offset RD offset for the time zone. Zero is assumed if this param is
5525 	 * not given
5526 	 * @return {number} the day of the week
5527 	 */
5528 	after: function(dayOfWeek, offset) {
5529 		offset = offset || 0;
5530 		return this._onOrBefore(this.rd+7+offset, dayOfWeek) - offset;
5531 	},
5532 
5533 	/**
5534 	 * Return the unix time equivalent to this Gregorian date instance. Unix time is
5535 	 * the number of milliseconds since midnight on Jan 1, 1970 UTC. This method only
5536 	 * returns a valid number for dates between midnight, Jan 1, 1970 and  
5537 	 * Jan 19, 2038 at 3:14:07am when the unix time runs out. If this instance 
5538 	 * encodes a date outside of that range, this method will return -1.
5539 	 * 
5540 	 * @return {number} a number giving the unix time, or -1 if the date is outside the
5541 	 * valid unix time range
5542 	 */
5543 	getTime: function() {
5544 		// earlier than Jan 1, 1970
5545 		// or later than Jan 19, 2038 at 3:14:07am
5546 		var jd = this.getJulianDay();
5547 		if (jd < 2440587.5 || jd > 2465442.634803241) { 
5548 			return -1;
5549 		}
5550 	
5551 		// avoid the rounding errors in the floating point math by only using
5552 		// the whole days from the rd, and then calculating the milliseconds directly
5553 		return Math.round((jd - 2440587.5) * 86400000);
5554 	},
5555 
5556 	/**
5557 	 * Return the extended unix time equivalent to this Gregorian date instance. Unix time is
5558 	 * the number of milliseconds since midnight on Jan 1, 1970 UTC. Traditionally unix time
5559 	 * (or the type "time_t" in C/C++) is only encoded with a unsigned 32 bit integer, and thus 
5560 	 * runs out on Jan 19, 2038. However, most Javascript engines encode numbers well above 
5561 	 * 32 bits and the Date object allows you to encode up to 100 million days worth of time 
5562 	 * after Jan 1, 1970, and even more interestingly 100 million days worth of time before
5563 	 * Jan 1, 1970 as well. This method returns the number of milliseconds in that extended 
5564 	 * range. If this instance encodes a date outside of that range, this method will return
5565 	 * NaN.
5566 	 * 
5567 	 * @return {number} a number giving the extended unix time, or NaN if the date is outside 
5568 	 * the valid extended unix time range
5569 	 */
5570 	getTimeExtended: function() {
5571 		var jd = this.getJulianDay();
5572 		
5573 		// test if earlier than Jan 1, 1970 - 100 million days
5574 		// or later than Jan 1, 1970 + 100 million days
5575 		if (jd < -97559412.5 || jd > 102440587.5) { 
5576 			return NaN;
5577 		}
5578 	
5579 		// avoid the rounding errors in the floating point math by only using
5580 		// the whole days from the rd, and then calculating the milliseconds directly
5581 		return Math.round((jd - 2440587.5) * 86400000);
5582 	},
5583 
5584 	/**
5585 	 * Return the Julian Day equivalent to this calendar date as a number.
5586 	 * This returns the julian day in UTC.
5587 	 * 
5588 	 * @return {number} the julian date equivalent of this date
5589 	 */
5590 	getJulianDay: function() {
5591 		return this.rd + this.epoch;
5592 	},
5593 
5594 	/**
5595 	 * Return the Rata Die (fixed day) number of this RD date.
5596 	 * 
5597 	 * @return {number} the rd date as a number
5598 	 */
5599 	getRataDie: function() {
5600 		return this.rd;
5601 	}
5602 };
5603 
5604 
5605 /*< GregRataDie.js */
5606 /*
5607  * gregratadie.js - Represent the RD date number in the Gregorian calendar
5608  * 
5609  * Copyright © 2014-2015, JEDLSoft
5610  *
5611  * Licensed under the Apache License, Version 2.0 (the "License");
5612  * you may not use this file except in compliance with the License.
5613  * You may obtain a copy of the License at
5614  *
5615  *     http://www.apache.org/licenses/LICENSE-2.0
5616  *
5617  * Unless required by applicable law or agreed to in writing, software
5618  * distributed under the License is distributed on an "AS IS" BASIS,
5619  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
5620  *
5621  * See the License for the specific language governing permissions and
5622  * limitations under the License.
5623  */
5624 
5625 /* !depends 
5626 ilib.js
5627 GregorianCal.js
5628 RataDie.js
5629 MathUtils.js
5630 */
5631 
5632 
5633 /**
5634  * @class
5635  * Construct a new Gregorian RD date number object. The constructor parameters can 
5636  * contain any of the following properties:
5637  * 
5638  * <ul>
5639  * <li><i>unixtime<i> - sets the time of this instance according to the given 
5640  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970.
5641  * 
5642  * <li><i>julianday</i> - sets the time of this instance according to the given
5643  * Julian Day instance or the Julian Day given as a float
5644  * 
5645  * <li><i>year</i> - any integer, including 0
5646  * 
5647  * <li><i>month</i> - 1 to 12, where 1 means January, 2 means February, etc.
5648  * 
5649  * <li><i>day</i> - 1 to 31
5650  * 
5651  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
5652  * is always done with an unambiguous 24 hour representation
5653  * 
5654  * <li><i>minute</i> - 0 to 59
5655  * 
5656  * <li><i>second</i> - 0 to 59
5657  * 
5658  * <li><i>millisecond</i> - 0 to 999
5659  * 
5660  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
5661  * </ul>
5662  *
5663  * If the constructor is called with another Gregorian date instance instead of
5664  * a parameter block, the other instance acts as a parameter block and its
5665  * settings are copied into the current instance.<p>
5666  * 
5667  * If the constructor is called with no arguments at all or if none of the 
5668  * properties listed above are present, then the RD is calculate based on 
5669  * the current date at the time of instantiation. <p>
5670  * 
5671  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
5672  * specified in the params, it is assumed that they have the smallest possible
5673  * value in the range for the property (zero or one).<p>
5674  * 
5675  * 
5676  * @private
5677  * @constructor
5678  * @extends RataDie
5679  * @param {Object=} params parameters that govern the settings and behaviour of this Gregorian RD date
5680  */
5681 var GregRataDie = function(params) {
5682 	this.cal = params && params.cal || new GregorianCal();
5683 	/** @type {number|undefined} */
5684 	this.rd = NaN;
5685 	RataDie.call(this, params);
5686 };
5687 
5688 GregRataDie.prototype = new RataDie();
5689 GregRataDie.prototype.parent = RataDie;
5690 GregRataDie.prototype.constructor = GregRataDie;
5691 
5692 /**
5693  * the cumulative lengths of each month, for a non-leap year 
5694  * @private
5695  * @const
5696  * @type Array.<number>
5697  */
5698 GregRataDie.cumMonthLengths = [
5699     0,   /* Jan */
5700 	31,  /* Feb */
5701 	59,  /* Mar */
5702 	90,  /* Apr */
5703 	120, /* May */
5704 	151, /* Jun */
5705 	181, /* Jul */
5706 	212, /* Aug */
5707 	243, /* Sep */
5708 	273, /* Oct */
5709 	304, /* Nov */
5710 	334, /* Dec */
5711 	365
5712 ];
5713 
5714 /**
5715  * the cumulative lengths of each month, for a leap year 
5716  * @private
5717  * @const
5718  * @type Array.<number>
5719  */
5720 GregRataDie.cumMonthLengthsLeap = [
5721 	0,   /* Jan */
5722 	31,  /* Feb */
5723 	60,  /* Mar */
5724 	91,  /* Apr */
5725 	121, /* May */
5726 	152, /* Jun */
5727 	182, /* Jul */
5728 	213, /* Aug */
5729 	244, /* Sep */
5730 	274, /* Oct */
5731 	305, /* Nov */
5732 	335, /* Dec */
5733 	366
5734 ];
5735 
5736 /**
5737  * Calculate the Rata Die (fixed day) number of the given date.
5738  * 
5739  * @private
5740  * @param {Object} date the date components to calculate the RD from
5741  */
5742 GregRataDie.prototype._setDateComponents = function(date) {
5743 	var year = parseInt(date.year, 10) || 0;
5744 	var month = parseInt(date.month, 10) || 1;
5745 	var day = parseInt(date.day, 10) || 1;
5746 	var hour = parseInt(date.hour, 10) || 0;
5747 	var minute = parseInt(date.minute, 10) || 0;
5748 	var second = parseInt(date.second, 10) || 0;
5749 	var millisecond = parseInt(date.millisecond, 10) || 0;
5750 
5751 	var years = 365 * (year - 1) +
5752 		Math.floor((year-1)/4) -
5753 		Math.floor((year-1)/100) +
5754 		Math.floor((year-1)/400);
5755 	
5756 	var dayInYear = (month > 1 ? GregRataDie.cumMonthLengths[month-1] : 0) +
5757 		day +
5758 		(GregorianCal.prototype.isLeapYear.call(this.cal, year) && month > 2 ? 1 : 0);
5759 	var rdtime = (hour * 3600000 +
5760 		minute * 60000 +
5761 		second * 1000 +
5762 		millisecond) / 
5763 		86400000; 
5764 	/*
5765 	debug("getRataDie: converting " +  JSON.stringify(this));
5766 	debug("getRataDie: year is " +  years);
5767 	debug("getRataDie: day in year is " +  dayInYear);
5768 	debug("getRataDie: rdtime is " +  rdtime);
5769 	debug("getRataDie: rd is " +  (years + dayInYear + rdtime));
5770 	*/
5771 	
5772 	/**
5773 	 * @type {number|undefined} the RD number of this Gregorian date
5774 	 */
5775 	this.rd = years + dayInYear + rdtime;
5776 };
5777 
5778 /**
5779  * Return the rd number of the particular day of the week on or before the 
5780  * given rd. eg. The Sunday on or before the given rd.
5781  * @private
5782  * @param {number} rd the rata die date of the reference date
5783  * @param {number} dayOfWeek the day of the week that is being sought relative 
5784  * to the current date
5785  * @return {number} the rd of the day of the week
5786  */
5787 GregRataDie.prototype._onOrBefore = function(rd, dayOfWeek) {
5788 	return rd - MathUtils.mod(Math.floor(rd) - dayOfWeek, 7);
5789 };
5790 
5791 
5792 /*< TimeZone.js */
5793 /*
5794  * TimeZone.js - Definition of a time zone class
5795  * 
5796  * Copyright © 2012-2015, JEDLSoft
5797  *
5798  * Licensed under the Apache License, Version 2.0 (the "License");
5799  * you may not use this file except in compliance with the License.
5800  * You may obtain a copy of the License at
5801  *
5802  *     http://www.apache.org/licenses/LICENSE-2.0
5803  *
5804  * Unless required by applicable law or agreed to in writing, software
5805  * distributed under the License is distributed on an "AS IS" BASIS,
5806  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
5807  *
5808  * See the License for the specific language governing permissions and
5809  * limitations under the License.
5810  */
5811 
5812 /*
5813 !depends 
5814 ilib.js 
5815 Locale.js
5816 LocaleInfo.js
5817 Utils.js
5818 MathUtils.js
5819 JSUtils.js
5820 GregRataDie.js
5821 IString.js
5822 CalendarFactory.js
5823 */
5824 
5825 // !data localeinfo zoneinfo
5826 
5827 
5828 
5829 
5830 /**
5831  * @class
5832  * Create a time zone instance. 
5833  * 
5834  * This class reports and transforms
5835  * information about particular time zones.<p>
5836  * 
5837  * The options parameter may contain any of the following properties:
5838  * 
5839  * <ul>
5840  * <li><i>id</i> - The id of the requested time zone such as "Europe/London" or 
5841  * "America/Los_Angeles". These are taken from the IANA time zone database. (See
5842  * http://www.iana.org/time-zones for more information.) <p>
5843  * 
5844  * There is one special 
5845  * time zone that is not taken from the IANA database called simply "local". In
5846  * this case, this class will attempt to discover the current time zone and
5847  * daylight savings time settings by calling standard Javascript classes to 
5848  * determine the offsets from UTC. 
5849  * 
5850  * <li><i>locale</i> - The locale for this time zone.
5851  * 
5852  * <li><i>offset</i> - Choose the time zone based on the offset from UTC given in
5853  * number of minutes (negative is west, positive is east).
5854  * 
5855  * <li><i>onLoad</i> - a callback function to call when the data is fully 
5856  * loaded. When the onLoad option is given, this class will attempt to
5857  * load any missing locale data using the ilib loader callback.
5858  * When the data is loaded, the onLoad function is called with the current 
5859  * instance as a parameter. 
5860  * 
5861  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
5862  * asynchronously. If this option is given as "false", then the "onLoad"
5863  * callback must be given, as the instance returned from this constructor will
5864  * not be usable for a while.
5865  *  
5866  * <li><i>loadParams</i> - an object containing parameters to pass to the 
5867  * loader callback function when locale data is missing. The parameters are not
5868  * interpretted or modified in any way. They are simply passed along. The object 
5869  * may contain any property/value pairs as long as the calling code is in
5870  * agreement with the loader callback function as to what those parameters mean.
5871  * </ul>
5872  * 
5873  * There is currently no way in the ECMAscript
5874  * standard to tell which exact time zone is currently in use. Choosing the
5875  * id "locale" or specifying an explicit offset will not give a specific time zone, 
5876  * as it is impossible to tell with certainty which zone the offsets 
5877  * match.<p>
5878  * 
5879  * When the id "local" is given or the offset option is specified, this class will
5880  * have the following behaviours:
5881  * <ul>
5882  * <li>The display name will always be given as the RFC822 style, no matter what
5883  * style is requested
5884  * <li>The id will also be returned as the RFC822 style display name
5885  * <li>When the offset is explicitly given, this class will assume the time zone 
5886  * does not support daylight savings time, and the offsets will be calculated 
5887  * the same way year round.
5888  * <li>When the offset is explicitly given, the inDaylightSavings() method will 
5889  * always return false.
5890  * <li>When the id "local" is given, this class will attempt to determine the 
5891  * daylight savings time settings by examining the offset from UTC on Jan 1
5892  * and June 1 of the current year. If they are different, this class assumes
5893  * that the local time zone uses DST. When the offset for a particular date is
5894  * requested, it will use the built-in Javascript support to determine the 
5895  * offset for that date.
5896  * </ul> 
5897  * 
5898  * If a more specific time zone is 
5899  * needed with display names and known start/stop times for DST, use the "id" 
5900  * property instead to specify the time zone exactly. You can perhaps ask the
5901  * user which time zone they prefer so that your app does not need to guess.<p>
5902  * 
5903  * If the id and the offset are both not given, the default time zone for the 
5904  * locale is retrieved from
5905  * the locale info. If the locale is not specified, the default locale for the
5906  * library is used.<p>
5907  * 
5908  * Because this class was designed for use in web sites, and the vast majority
5909  * of dates and times being formatted are recent date/times, this class is simplified
5910  * by not implementing historical time zones. That is, when governments change the 
5911  * time zone rules for a particular zone, only the latest such rule is implemented 
5912  * in this class. That means that determining the offset for a date that is prior 
5913  * to the last change may give the wrong result. Historical time zone calculations
5914  * may be implemented in a later version of iLib if there is enough demand for it,
5915  * but it would entail a much larger set of time zone data that would have to be
5916  * loaded.  
5917  * 
5918  * 
5919  * @constructor
5920  * @param {Object} options Options guiding the construction of this time zone instance
5921  */
5922 var TimeZone = function(options) {
5923 	this.sync = true;
5924 	this.locale = new Locale();
5925 	this.isLocal = false;
5926 	
5927 	if (options) {
5928 		if (options.locale) {
5929 			this.locale = (typeof(options.locale) === 'string') ? new Locale(options.locale) : options.locale;
5930 		}
5931 		
5932 		if (options.id) {
5933 			var id = options.id.toString();
5934 			if (id === 'local') {
5935 				this.isLocal = true;
5936 				
5937 				// use standard Javascript Date to figure out the time zone offsets
5938 				var now = new Date(), 
5939 					jan1 = new Date(now.getFullYear(), 0, 1),  // months in std JS Date object are 0-based
5940 					jun1 = new Date(now.getFullYear(), 5, 1);
5941 				
5942 				// Javascript's method returns the offset backwards, so we have to
5943 				// take the negative to get the correct offset
5944 				this.offsetJan1 = -jan1.getTimezoneOffset();
5945 				this.offsetJun1 = -jun1.getTimezoneOffset();
5946 				// the offset of the standard time for the time zone is always the one that is closest 
5947 				// to negative infinity of the two, no matter whether you are in the northern or southern 
5948 				// hemisphere, east or west
5949 				this.offset = Math.min(this.offsetJan1, this.offsetJun1);
5950 			}
5951 			this.id = id;
5952 		} else if (options.offset) {
5953 			this.offset = (typeof(options.offset) === 'string') ? parseInt(options.offset, 10) : options.offset;
5954 			this.id = this.getDisplayName(undefined, undefined);
5955 		}
5956 		
5957 		if (typeof(options.sync) !== 'undefined') {
5958 			this.sync = !!options.sync;
5959 		}
5960 		
5961 		this.loadParams = options.loadParams;
5962 		this.onLoad = options.onLoad;
5963 	}
5964 
5965 	//console.log("timezone: locale is " + this.locale);
5966 	
5967 	if (!this.id) {
5968 		new LocaleInfo(this.locale, {
5969 			sync: this.sync,
5970 			onLoad: ilib.bind(this, function (li) {
5971 				this.id = li.getTimeZone() || "Etc/UTC";
5972 				this._loadtzdata();
5973 			})
5974 		});
5975 	} else {
5976 		this._loadtzdata();
5977 	}
5978 
5979 	//console.log("localeinfo is: " + JSON.stringify(this.locinfo));
5980 	//console.log("id is: " + JSON.stringify(this.id));
5981 };
5982 
5983 /*
5984  * Explanation of the compressed time zone info properties.
5985  * {
5986  *     "o": "8:0",      // offset from UTC
5987  *     "f": "W{c}T",    // standard abbreviation. For time zones that observe DST, the {c} replacement is replaced with the 
5988  *                      // letter in the e.c or s.c properties below 
5989  *     "e": {           // info about the end of DST
5990  *         "j": 78322.5 // Julian day when the transition happens. Either specify the "j" property or all of the "m", "r", and 
5991  *                      // "t" properties, but not both sets.
5992  *         "m": 3,      // month that it ends
5993  *         "r": "l0",   // rule for the day it ends "l" = "last", numbers are Sun=0 through Sat=6. Other syntax is "0>7". 
5994  *                      // This means the 0-day (Sun) after the 7th of the month. Other possible operators are <, >, <=, >=
5995  *         "t": "2:0",  // time of day that the DST turns off, hours:minutes
5996  *         "c": "S"     // character to replace into the abbreviation for standard time 
5997  *     },
5998  *     "s": {           // info about the start of DST
5999  *         "j": 78189.5 // Julian day when the transition happens. Either specify the "j" property or all of the "m", "r", and 
6000  *                      // "t" properties, but not both sets.
6001  *         "m": 10,     // month that it starts
6002  *         "r": "l0",   // rule for the day it starts "l" = "last", numbers are Sun=0 through Sat=6. Other syntax is "0>7".
6003  *                      // This means the 0-day (Sun) after the 7th of the month. Other possible operators are <, >, <=, >=
6004  *         "t": "2:0",  // time of day that the DST turns on, hours:minutes
6005  *         "v": "1:0",  // amount of time saved in hours:minutes
6006  *         "c": "D"     // character to replace into the abbreviation for daylight time
6007  *     },
6008  *     "c": "AU",       // ISO code for the country that contains this time zone
6009  *     "n": "W. Australia {c} Time"
6010  *                      // long English name of the zone. The {c} replacement is for the word "Standard" or "Daylight" as appropriate
6011  * }
6012  */
6013 TimeZone.prototype._loadtzdata = function () {
6014 	var zoneName = this.id.replace(/-/g, "m").replace(/\+/g, "p");
6015 	// console.log("id is: " + JSON.stringify(this.id));
6016 	// console.log("zoneinfo is: " + JSON.stringify(ilib.data.zoneinfo[zoneName]));
6017 	if (!ilib.data.zoneinfo[zoneName] && typeof(this.offset) === 'undefined') {
6018 		Utils.loadData({
6019 			object: TimeZone, 
6020 			nonlocale: true,	// locale independent 
6021 			name: "zoneinfo/" + this.id + ".json", 
6022 			sync: this.sync, 
6023 			loadParams: this.loadParams, 
6024 			callback: ilib.bind(this, function (tzdata) {
6025 				if (tzdata && !JSUtils.isEmpty(tzdata)) {
6026 					ilib.data.zoneinfo[zoneName] = tzdata;
6027 				}
6028 				this._initZone(zoneName);
6029 			})
6030 		});
6031 	} else {
6032 		this._initZone(zoneName);
6033 	}
6034 };
6035 
6036 TimeZone.prototype._initZone = function(zoneName) {
6037 	/** 
6038 	 * @private
6039 	 * @type {{o:string,f:string,e:Object.<{m:number,r:string,t:string,z:string}>,s:Object.<{m:number,r:string,t:string,z:string,v:string,c:string}>,c:string,n:string}} 
6040 	 */
6041 	this.zone = ilib.data.zoneinfo[zoneName];
6042 	if (!this.zone && typeof(this.offset) === 'undefined') {
6043 		this.id = "Etc/UTC";
6044 		this.zone = ilib.data.zoneinfo[this.id];
6045 	}
6046 	
6047 	this._calcDSTSavings();
6048 	
6049 	if (typeof(this.offset) === 'undefined' && this.zone.o) {
6050 		var offsetParts = this._offsetStringToObj(this.zone.o);
6051 		/**
6052 		 * @private
6053 		 * @type {number} raw offset from UTC without DST, in minutes
6054 		 */
6055 		this.offset = (Math.abs(offsetParts.h || 0) * 60 + (offsetParts.m || 0)) * MathUtils.signum(offsetParts.h || 0);
6056 	}
6057 	
6058 	if (this.onLoad && typeof(this.onLoad) === 'function') {
6059 		this.onLoad(this);
6060 	}
6061 };
6062 
6063 /** @private */
6064 TimeZone._marshallIds = function (country, sync, callback) {
6065 	var tz, ids = [];
6066 	
6067 	if (!country) {
6068 		// local is a special zone meaning "the local time zone according to the JS engine we are running upon"
6069 		ids.push("local");
6070 		for (tz in ilib.data.timezones) {
6071 			if (ilib.data.timezones[tz]) {
6072 				ids.push(ilib.data.timezones[tz]);
6073 			}
6074 		}
6075 		if (typeof(callback) === 'function') {
6076 			callback(ids);
6077 		}
6078 	} else {
6079 		if (!ilib.data.zoneinfo.zonetab) {
6080 			Utils.loadData({
6081 				object: TimeZone, 
6082 				nonlocale: true,	// locale independent 
6083 				name: "zoneinfo/zonetab.json", 
6084 				sync: sync, 
6085 				callback: ilib.bind(this, function (tzdata) {
6086 					if (tzdata) {
6087 						ilib.data.zoneinfo.zonetab = tzdata;
6088 					}
6089 					
6090 					ids = ilib.data.zoneinfo.zonetab[country];
6091 					
6092 					if (typeof(callback) === 'function') {
6093 						callback(ids);
6094 					}
6095 				})
6096 			});
6097 		} else {
6098 			ids = ilib.data.zoneinfo.zonetab[country];
6099 			if (typeof(callback) === 'function') {
6100 				callback(ids);
6101 			}
6102 		}
6103 	}
6104 	
6105 	return ids;
6106 };
6107 
6108 /**
6109  * Return an array of available zone ids that the constructor knows about.
6110  * The country parameter is optional. If it is not given, all time zones will
6111  * be returned. If it specifies a country code, then only time zones for that
6112  * country will be returned.
6113  * 
6114  * @param {string|undefined} country country code for which time zones are being sought
6115  * @param {boolean} sync whether to find the available ids synchronously (true) or asynchronously (false)
6116  * @param {function(Array.<string>)} onLoad callback function to call when the data is finished loading
6117  * @return {Array.<string>} an array of zone id strings
6118  */
6119 TimeZone.getAvailableIds = function (country, sync, onLoad) {
6120 	var tz, ids = [];
6121 	
6122 	if (typeof(sync) !== 'boolean') {
6123 		sync = true;
6124 	}
6125 	
6126 	if (ilib.data.timezones.length === 0) {
6127 		if (typeof(ilib._load) !== 'undefined' && typeof(ilib._load.listAvailableFiles) === 'function') {
6128 			ilib._load.listAvailableFiles(sync, function(hash) {
6129 				for (var dir in hash) {
6130 					var files = hash[dir];
6131 					if (ilib.isArray(files)) {
6132 						files.forEach(function (filename) {
6133 							if (filename && filename.match(/^zoneinfo/)) {
6134 								ilib.data.timezones.push(filename.replace(/^zoneinfo\//, "").replace(/\.json$/, ""));
6135 							}
6136 						});
6137 					}
6138 				}
6139 				ids = TimeZone._marshallIds(country, sync, onLoad);
6140 			});
6141 		} else {
6142 			for (tz in ilib.data.zoneinfo) {
6143 				if (ilib.data.zoneinfo[tz]) {
6144 					ilib.data.timezones.push(tz);
6145 				}
6146 			}
6147 			ids = TimeZone._marshallIds(country, sync, onLoad);
6148 		}
6149 	} else {
6150 		ids = TimeZone._marshallIds(country, sync, onLoad);
6151 	}
6152 	
6153 	return ids;
6154 };
6155 
6156 /**
6157  * Return the id used to uniquely identify this time zone.
6158  * @return {string} a unique id for this time zone
6159  */
6160 TimeZone.prototype.getId = function () {
6161 	return this.id.toString();
6162 };
6163 
6164 /**
6165  * Return the abbreviation that is used for the current time zone on the given date.
6166  * The date may be in DST or during standard time, and many zone names have different
6167  * abbreviations depending on whether or not the date is falls within DST.<p>
6168  * 
6169  * There are two styles that are supported:
6170  * 
6171  * <ol>
6172  * <li>standard - returns the 3 to 5 letter abbreviation of the time zone name such 
6173  * as "CET" for "Central European Time" or "PDT" for "Pacific Daylight Time"
6174  * <li>rfc822 - returns an RFC 822 style time zone specifier, which specifies more
6175  * explicitly what the offset is from UTC
6176  * <li>long - returns the long name of the zone in English
6177  * </ol>
6178  *  
6179  * @param {IDate=} date a date to determine if it is in daylight time or standard time
6180  * @param {string=} style one of "standard" or "rfc822". Default if not specified is "standard"
6181  * @return {string} the name of the time zone, abbreviated according to the style 
6182  */
6183 TimeZone.prototype.getDisplayName = function (date, style) {
6184 	style = (this.isLocal || typeof(this.zone) === 'undefined') ? "rfc822" : (style || "standard");
6185 	switch (style) {
6186 		default:
6187 		case 'standard':
6188 			if (this.zone.f && this.zone.f !== "zzz") {
6189 				if (this.zone.f.indexOf("{c}") !== -1) {
6190 					var letter = "";
6191 					letter = this.inDaylightTime(date) ? this.zone.s && this.zone.s.c : this.zone.e && this.zone.e.c; 
6192 					var temp = new IString(this.zone.f);
6193 					return temp.format({c: letter || ""});
6194 				}
6195 				return this.zone.f;
6196 			} 
6197 			var temp = "GMT" + this.zone.o;
6198 			if (this.inDaylightTime(date)) {
6199 				temp += "+" + this.zone.s.v;
6200 			}
6201 			return temp;
6202 			break;
6203 		case 'rfc822':
6204 			var offset = this.getOffset(date), // includes the DST if applicable
6205 				ret = "UTC",
6206 				hour = offset.h || 0,
6207 				minute = offset.m || 0;
6208 			
6209 			if (hour !== 0) {
6210 				ret += (hour > 0) ? "+" : "-";
6211 				if (Math.abs(hour) < 10) {
6212 					ret += "0";
6213 				}
6214 				ret += (hour < 0) ? -hour : hour;
6215 				if (minute < 10) {
6216 					ret += "0";
6217 				}
6218 				ret += minute;
6219 			}
6220 			return ret; 
6221 		case 'long':
6222 			if (this.zone.n) {
6223 				if (this.zone.n.indexOf("{c}") !== -1) {
6224 					var str = this.inDaylightTime(date) ? "Daylight" : "Standard"; 
6225 					var temp = new IString(this.zone.n);
6226 					return temp.format({c: str || ""});
6227 				}
6228 				return this.zone.n;
6229 			}
6230 			var temp = "GMT" + this.zone.o;
6231 			if (this.inDaylightTime(date)) {
6232 				temp += "+" + this.zone.s.v;
6233 			}
6234 			return temp;
6235 			break;
6236 	}
6237 };
6238 
6239 /**
6240  * Convert the offset string to an object with an h, m, and possibly s property
6241  * to indicate the hours, minutes, and seconds.
6242  * 
6243  * @private
6244  * @param {string} str the offset string to convert to an object
6245  * @return {Object.<{h:number,m:number,s:number}>} an object giving the offset for the zone at 
6246  * the given date/time, in hours, minutes, and seconds
6247  */
6248 TimeZone.prototype._offsetStringToObj = function (str) {
6249 	var offsetParts = (typeof(str) === 'string') ? str.split(":") : [],
6250 		ret = {h:0},
6251 		temp;
6252 	
6253 	if (offsetParts.length > 0) {
6254 		ret.h = parseInt(offsetParts[0], 10);
6255 		if (offsetParts.length > 1) {
6256 			temp = parseInt(offsetParts[1], 10);
6257 			if (temp) {
6258 				ret.m = temp;
6259 			}
6260 			if (offsetParts.length > 2) {
6261 				temp = parseInt(offsetParts[2], 10);
6262 				if (temp) {
6263 					ret.s = temp;
6264 				}
6265 			}
6266 		}
6267 	}
6268 
6269 	return ret;
6270 };
6271 
6272 /**
6273  * Returns the offset of this time zone from UTC at the given date/time. If daylight saving 
6274  * time is in effect at the given date/time, this method will return the offset value 
6275  * adjusted by the amount of daylight saving.
6276  * @param {IDate=} date the date for which the offset is needed
6277  * @return {Object.<{h:number,m:number}>} an object giving the offset for the zone at 
6278  * the given date/time, in hours, minutes, and seconds  
6279  */
6280 TimeZone.prototype.getOffset = function (date) {
6281 	if (!date) {
6282 		return this.getRawOffset();
6283 	}
6284 	var offset = this.getOffsetMillis(date)/60000;
6285 	
6286 	var hours = MathUtils.down(offset/60),
6287 		minutes = Math.abs(offset) - Math.abs(hours)*60;
6288 
6289 	var ret = {
6290 		h: hours
6291 	};
6292 	if (minutes != 0) {
6293 		ret.m = minutes;
6294 	}
6295 	return ret;
6296 };
6297 
6298 /**
6299  * Returns the offset of this time zone from UTC at the given date/time expressed in 
6300  * milliseconds. If daylight saving 
6301  * time is in effect at the given date/time, this method will return the offset value 
6302  * adjusted by the amount of daylight saving. Negative numbers indicate offsets west
6303  * of UTC and conversely, positive numbers indicate offset east of UTC.
6304  *  
6305  * @param {IDate=} date the date for which the offset is needed, or null for the
6306  * present date
6307  * @return {number} the number of milliseconds of offset from UTC that the given date is
6308  */
6309 TimeZone.prototype.getOffsetMillis = function (date) {
6310 	var ret;
6311 	
6312 	// check if the dst property is defined -- the intrinsic JS Date object doesn't work so
6313 	// well if we are in the overlap time at the end of DST
6314 	if (this.isLocal && typeof(date.dst) === 'undefined') {
6315 		var d = (!date) ? new Date() : new Date(date.getTimeExtended());
6316 		return -d.getTimezoneOffset() * 60000;
6317 	} 
6318 	
6319 	ret = this.offset;
6320 	
6321 	if (date && this.inDaylightTime(date)) {
6322 		ret += this.dstSavings;
6323 	}
6324 	
6325 	return ret * 60000;
6326 };
6327 
6328 /**
6329  * Return the offset in milliseconds when the date has an RD number in wall
6330  * time rather than in UTC time.
6331  * @protected
6332  * @param date the date to check in wall time
6333  * @returns {number} the number of milliseconds of offset from UTC that the given date is
6334  */
6335 TimeZone.prototype._getOffsetMillisWallTime = function (date) {
6336 	var ret;
6337 	
6338 	ret = this.offset;
6339 	
6340 	if (date && this.inDaylightTime(date, true)) {
6341 		ret += this.dstSavings;
6342 	}
6343 	
6344 	return ret * 60000;
6345 };
6346 
6347 /**
6348  * Returns the offset of this time zone from UTC at the given date/time. If daylight saving 
6349  * time is in effect at the given date/time, this method will return the offset value 
6350  * adjusted by the amount of daylight saving.
6351  * @param {IDate=} date the date for which the offset is needed
6352  * @return {string} the offset for the zone at the given date/time as a string in the 
6353  * format "h:m:s" 
6354  */
6355 TimeZone.prototype.getOffsetStr = function (date) {
6356 	var offset = this.getOffset(date),
6357 		ret;
6358 	
6359 	ret = offset.h;
6360 	if (typeof(offset.m) !== 'undefined') {
6361 		ret += ":" + offset.m;
6362 		if (typeof(offset.s) !== 'undefined') {
6363 			ret += ":" + offset.s;
6364 		}
6365 	} else {
6366 		ret += ":0";
6367 	}
6368 	
6369 	return ret;
6370 };
6371 
6372 /**
6373  * Gets the offset from UTC for this time zone.
6374  * @return {Object.<{h:number,m:number,s:number}>} an object giving the offset from 
6375  * UTC for this time zone, in hours, minutes, and seconds 
6376  */
6377 TimeZone.prototype.getRawOffset = function () {
6378 	var hours = MathUtils.down(this.offset/60),
6379 		minutes = Math.abs(this.offset) - Math.abs(hours)*60;
6380 	
6381 	var ret = {
6382 		h: hours
6383 	};
6384 	if (minutes != 0) {
6385 		ret.m = minutes;
6386 	}
6387 	return ret;
6388 };
6389 
6390 /**
6391  * Gets the offset from UTC for this time zone expressed in milliseconds. Negative numbers
6392  * indicate zones west of UTC, and positive numbers indicate zones east of UTC.
6393  * 
6394  * @return {number} an number giving the offset from 
6395  * UTC for this time zone in milliseconds 
6396  */
6397 TimeZone.prototype.getRawOffsetMillis = function () {
6398 	return this.offset * 60000;
6399 };
6400 
6401 /**
6402  * Gets the offset from UTC for this time zone without DST savings.
6403  * @return {string} the offset from UTC for this time zone, in the format "h:m:s" 
6404  */
6405 TimeZone.prototype.getRawOffsetStr = function () {
6406 	var off = this.getRawOffset();
6407 	return off.h + ":" + (off.m || "0");
6408 };
6409 
6410 /**
6411  * Return the amount of time in hours:minutes that the clock is advanced during
6412  * daylight savings time.
6413  * @return {Object.<{h:number,m:number,s:number}>} the amount of time that the 
6414  * clock advances for DST in hours, minutes, and seconds 
6415  */
6416 TimeZone.prototype.getDSTSavings = function () {
6417 	if (this.isLocal) {
6418 		// take the absolute because the difference in the offsets may be positive or
6419 		// negative, depending on the hemisphere
6420 		var savings = Math.abs(this.offsetJan1 - this.offsetJun1);
6421 		var hours = MathUtils.down(savings/60),
6422 			minutes = savings - hours*60;
6423 		return {
6424 			h: hours,
6425 			m: minutes
6426 		};
6427 	} else if (this.zone && this.zone.s) {
6428 		return this._offsetStringToObj(this.zone.s.v);	// this.zone.start.savings
6429 	}
6430 	return {h:0};
6431 };
6432 
6433 /**
6434  * Return the amount of time in hours:minutes that the clock is advanced during
6435  * daylight savings time.
6436  * @return {string} the amount of time that the clock advances for DST in the
6437  * format "h:m:s"
6438  */
6439 TimeZone.prototype.getDSTSavingsStr = function () {
6440 	if (this.isLocal) {
6441 		var savings = this.getDSTSavings();
6442 		return savings.h + ":" + savings.m;
6443 	} else if (typeof(this.offset) !== 'undefined' && this.zone && this.zone.s) {
6444 		return this.zone.s.v;	// this.zone.start.savings
6445 	}
6446 	return "0:0";
6447 };
6448 
6449 /**
6450  * return the rd of the start of DST transition for the given year
6451  * @protected
6452  * @param {Object} rule set of rules
6453  * @param {number} year year to check
6454  * @return {number} the rd of the start of DST for the year
6455  */
6456 TimeZone.prototype._calcRuleStart = function (rule, year) {
6457 	var type = "=", 
6458 		weekday = 0, 
6459 		day, 
6460 		refDay, 
6461 		cal, 
6462 		hour = 0, 
6463 		minute = 0, 
6464 		second = 0,
6465 		time,
6466 		i;
6467 	
6468 	if (typeof(rule.j) !== 'undefined') {
6469 		refDay = new GregRataDie({
6470 			julianday: rule.j
6471 		});
6472 	} else {
6473 		if (rule.r.charAt(0) == 'l' || rule.r.charAt(0) == 'f') {
6474 			cal = CalendarFactory({type: "gregorian"});
6475 			type = rule.r.charAt(0);
6476 			weekday = parseInt(rule.r.substring(1), 10);
6477 			day = (type === 'l') ? cal.getMonLength(rule.m, year) : 1;
6478 			//console.log("_calcRuleStart: Calculating the " + 
6479 			//		(rule.r.charAt(0) == 'f' ? "first " : "last ") + weekday + 
6480 			//		" of month " + rule.m);
6481 		} else {
6482 			i = rule.r.indexOf('<');
6483 			if (i == -1) {
6484 				i = rule.r.indexOf('>');
6485 			}
6486 			
6487 			if (i != -1) {
6488 				type = rule.r.charAt(i);
6489 				weekday = parseInt(rule.r.substring(0, i), 10);
6490 				day = parseInt(rule.r.substring(i+1), 10); 
6491 				//console.log("_calcRuleStart: Calculating the " + weekday + 
6492 				//		type + day + " of month " + rule.m);
6493 			} else {
6494 				day = parseInt(rule.r, 10);
6495 				//console.log("_calcRuleStart: Calculating the " + day + " of month " + rule.m);
6496 			}
6497 		}
6498 	
6499 		if (rule.t) {
6500 			time = rule.t.split(":");
6501 			hour = parseInt(time[0], 10);
6502 			if (time.length > 1) {
6503 				minute = parseInt(time[1], 10);
6504 				if (time.length > 2) {
6505 					second = parseInt(time[2], 10);
6506 				}
6507 			}
6508 		}
6509 		//console.log("calculating rd of " + year + "/" + rule.m + "/" + day);
6510 		refDay = new GregRataDie({
6511 			year: year, 
6512 			month: rule.m, 
6513 			day: day, 
6514 			hour: hour, 
6515 			minute: minute, 
6516 			second: second
6517 		});
6518 	}
6519 	//console.log("refDay is " + JSON.stringify(refDay));
6520 	var d = refDay.getRataDie();
6521 	
6522 	switch (type) {
6523 		case 'l':
6524 		case '<':
6525 			//console.log("returning " + refDay.onOrBefore(rd, weekday));
6526 			d = refDay.onOrBefore(weekday); 
6527 			break;
6528 		case 'f':
6529 		case '>':
6530 			//console.log("returning " + refDay.onOrAfterRd(rd, weekday));
6531 			d = refDay.onOrAfter(weekday); 
6532 			break;
6533 	}
6534 	return d;
6535 };
6536 
6537 /**
6538  * @private
6539  */
6540 TimeZone.prototype._calcDSTSavings = function () {
6541 	var saveParts = this.getDSTSavings();
6542 	
6543 	/**
6544 	 * @private
6545 	 * @type {number} savings in minutes when DST is in effect 
6546 	 */
6547 	this.dstSavings = (Math.abs(saveParts.h || 0) * 60 + (saveParts.m || 0)) * MathUtils.signum(saveParts.h || 0);
6548 };
6549 
6550 /**
6551  * @private
6552  */
6553 TimeZone.prototype._getDSTStartRule = function (year) {
6554 	// TODO: update this when historic/future zones are supported
6555 	return this.zone.s;
6556 };
6557 
6558 /**
6559  * @private
6560  */
6561 TimeZone.prototype._getDSTEndRule = function (year) {
6562 	// TODO: update this when historic/future zones are supported
6563 	return this.zone.e;
6564 };
6565 
6566 /**
6567  * Returns whether or not the given date is in daylight saving time for the current
6568  * zone. Note that daylight savings time is observed for the summer. Because
6569  * the seasons are reversed, daylight savings time in the southern hemisphere usually
6570  * runs from the end of the year through New Years into the first few months of the
6571  * next year. This method will correctly calculate the start and end of DST for any
6572  * location.
6573  * 
6574  * @param {IDate=} date a date for which the info about daylight time is being sought,
6575  * or undefined to tell whether we are currently in daylight savings time
6576  * @param {boolean=} wallTime if true, then the given date is in wall time. If false or
6577  * undefined, it is in the usual UTC time.
6578  * @return {boolean} true if the given date is in DST for the current zone, and false
6579  * otherwise.
6580  */
6581 TimeZone.prototype.inDaylightTime = function (date, wallTime) {
6582 	var rd, startRd, endRd, year;
6583 
6584 	if (this.isLocal) {
6585 		// check if the dst property is defined -- the intrinsic JS Date object doesn't work so
6586 		// well if we are in the overlap time at the end of DST, so we have to work around that
6587 		// problem by adding in the savings ourselves
6588 		var offset = 0;
6589 		if (typeof(date.dst) !== 'undefined' && !date.dst) {
6590 			offset = this.dstSavings * 60000;
6591 		}
6592 		
6593 		var d = new Date(date ? date.getTimeExtended() + offset: undefined);
6594 		// the DST offset is always the one that is closest to positive infinity, no matter 
6595 		// if you are in the northern or southern hemisphere, east or west
6596 		var dst = Math.max(this.offsetJan1, this.offsetJun1);
6597 		return (-d.getTimezoneOffset() === dst);
6598 	}
6599 	
6600 	if (!date || !date.cal || date.cal.type !== "gregorian") {
6601 		// convert to Gregorian so that we can tell if it is in DST or not
6602 		var time = date && typeof(date.getTimeExtended) === 'function' ? date.getTimeExtended() : undefined;
6603 		rd = new GregRataDie({unixtime: time}).getRataDie();
6604 		year = new Date(time).getUTCFullYear();
6605 	} else {
6606 		rd = date.rd.getRataDie();
6607 		year = date.year;
6608 	}
6609 	// rd should be a Gregorian RD number now, in UTC
6610 	
6611 	// if we aren't using daylight time in this zone for the given year, then we are 
6612 	// not in daylight time
6613 	if (!this.useDaylightTime(year)) {
6614 		return false;
6615 	}
6616 	
6617 	// these calculate the start/end in local wall time
6618 	var startrule = this._getDSTStartRule(year);
6619 	var endrule = this._getDSTEndRule(year);
6620 	startRd = this._calcRuleStart(startrule, year);
6621 	endRd = this._calcRuleStart(endrule, year);
6622 	
6623 	if (wallTime) {
6624 		// rd is in wall time, so we have to make sure to skip the missing time
6625 		// at the start of DST when standard time ends and daylight time begins
6626 		startRd += this.dstSavings/1440;
6627 	} else {
6628 		// rd is in UTC, so we have to convert the start/end to UTC time so 
6629 		// that they can be compared directly to the UTC rd number of the date
6630 		
6631 		// when DST starts, time is standard time already, so we only have
6632 		// to subtract the offset to get to UTC and not worry about the DST savings
6633 		startRd -= this.offset/1440;  
6634 		
6635 		// when DST ends, time is in daylight time already, so we have to
6636 		// subtract the DST savings to get back to standard time, then the
6637 		// offset to get to UTC
6638 		endRd -= (this.offset + this.dstSavings)/1440;
6639 	}
6640 	
6641 	// In the northern hemisphere, the start comes first some time in spring (Feb-Apr), 
6642 	// then the end some time in the fall (Sept-Nov). In the southern
6643 	// hemisphere, it is the other way around because the seasons are reversed. Standard
6644 	// time is still in the winter, but the winter months are May-Aug, and daylight 
6645 	// savings time usually starts Aug-Oct of one year and runs through Mar-May of the 
6646 	// next year.
6647 	if (rd < endRd && endRd - rd <= this.dstSavings/1440 && typeof(date.dst) === 'boolean') {
6648 		// take care of the magic overlap time at the end of DST
6649 		return date.dst;
6650 	}
6651 	if (startRd < endRd) {
6652 		// northern hemisphere
6653 		return (rd >= startRd && rd < endRd) ? true : false;
6654 	} 
6655 	// southern hemisphere
6656 	return (rd >= startRd || rd < endRd) ? true : false;
6657 };
6658 
6659 /**
6660  * Returns true if this time zone switches to daylight savings time at some point
6661  * in the year, and false otherwise.
6662  * @param {number} year Whether or not the time zone uses daylight time in the given year. If
6663  * this parameter is not given, the current year is assumed.
6664  * @return {boolean} true if the time zone uses daylight savings time
6665  */
6666 TimeZone.prototype.useDaylightTime = function (year) {
6667 	
6668 	// this zone uses daylight savings time iff there is a rule defining when to start
6669 	// and when to stop the DST
6670 	return (this.isLocal && this.offsetJan1 !== this.offsetJun1) ||
6671 		(typeof(this.zone) !== 'undefined' && 
6672 		typeof(this.zone.s) !== 'undefined' && 
6673 		typeof(this.zone.e) !== 'undefined');
6674 };
6675 
6676 /**
6677  * Returns the ISO 3166 code of the country for which this time zone is defined.
6678  * @return {string} the ISO 3166 code of the country for this zone
6679  */
6680 TimeZone.prototype.getCountry = function () {
6681 	return this.zone.c;
6682 };
6683 
6684 
6685 
6686 /*< SearchUtils.js */
6687 /*
6688  * SearchUtils.js - Misc search utility routines
6689  * 
6690  * Copyright © 2013-2015, JEDLSoft
6691  *
6692  * Licensed under the Apache License, Version 2.0 (the "License");
6693  * you may not use this file except in compliance with the License.
6694  * You may obtain a copy of the License at
6695  *
6696  *     http://www.apache.org/licenses/LICENSE-2.0
6697  *
6698  * Unless required by applicable law or agreed to in writing, software
6699  * distributed under the License is distributed on an "AS IS" BASIS,
6700  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
6701  *
6702  * See the License for the specific language governing permissions and
6703  * limitations under the License.
6704  */
6705 
6706 var SearchUtils = {};
6707 
6708 /**
6709  * Binary search a sorted array for a particular target value.
6710  * If the exact value is not found, it returns the index of the smallest 
6711  * entry that is greater than the given target value.<p> 
6712  * 
6713  * The comparator
6714  * parameter is a function that knows how to compare elements of the 
6715  * array and the target. The function should return a value greater than 0
6716  * if the array element is greater than the target, a value less than 0 if
6717  * the array element is less than the target, and 0 if the array element 
6718  * and the target are equivalent.<p>
6719  * 
6720  * If the comparator function is not specified, this function assumes
6721  * the array and the target are numeric values and should be compared 
6722  * as such.<p>
6723  * 
6724  * 
6725  * @static
6726  * @param {*} target element being sought 
6727  * @param {Array} arr the array being searched
6728  * @param {?function(*,*)=} comparator a comparator that is appropriate for comparing two entries
6729  * in the array  
6730  * @return the index of the array into which the value would fit if 
6731  * inserted, or -1 if given array is not an array or the target is not 
6732  * a number
6733  */
6734 SearchUtils.bsearch = function(target, arr, comparator) {
6735 	if (typeof(arr) === 'undefined' || !arr || typeof(target) === 'undefined') {
6736 		return -1;
6737 	}
6738 	
6739 	var high = arr.length - 1,
6740 		low = 0,
6741 		mid = 0,
6742 		value,
6743 		cmp = comparator || SearchUtils.bsearch.numbers;
6744 	
6745 	while (low <= high) {
6746 		mid = Math.floor((high+low)/2);
6747 		value = cmp(arr[mid], target);
6748 		if (value > 0) {
6749 			high = mid - 1;
6750 		} else if (value < 0) {
6751 			low = mid + 1;
6752 		} else {
6753 			return mid;
6754 		}
6755 	}
6756 	
6757 	return low;
6758 };
6759 
6760 /**
6761  * Returns whether or not the given element is greater than, less than,
6762  * or equal to the given target.<p>
6763  * 
6764  * @private
6765  * @static
6766  * @param {number} element the element being tested
6767  * @param {number} target the target being sought
6768  */
6769 SearchUtils.bsearch.numbers = function(element, target) {
6770 	return element - target;
6771 };
6772 
6773 /**
6774  * Do a bisection search of a function for a particular target value.<p> 
6775  * 
6776  * The function to search is a function that takes a numeric parameter, 
6777  * does calculations, and returns gives a numeric result. The 
6778  * function should should be smooth and not have any discontinuities 
6779  * between the low and high values of the parameter.
6780  *  
6781  * 
6782  * @static
6783  * @param {number} target value being sought
6784  * @param {number} low the lower bounds to start searching
6785  * @param {number} high the upper bounds to start searching
6786  * @param {number} precision minimum precision to support. Use 0 if you want to use the default.
6787  * @param {?function(number)=} func function to search 
6788  * @return an approximation of the input value to the function that gives the desired
6789  * target output value, correct to within the error range of Javascript floating point 
6790  * arithmetic, or NaN if there was some error
6791  */
6792 SearchUtils.bisectionSearch = function(target, low, high, precision, func) {
6793 	if (typeof(target) !== 'number' || 
6794 			typeof(low) !== 'number' || 
6795 			typeof(high) !== 'number' || 
6796 			typeof(func) !== 'function') {
6797 		return NaN;
6798 	}
6799 	
6800 	var mid = 0,
6801 		value,
6802 		pre = precision > 0 ? precision : 1e-13;
6803 	
6804 	do {
6805 		mid = (high+low)/2;
6806 		value = func(mid);
6807 		if (value > target) {
6808 			high = mid;
6809 		} else if (value < target) {
6810 			low = mid;
6811 		}
6812 	} while (high - low > pre);
6813 	
6814 	return mid;
6815 };
6816 
6817 
6818 
6819 /*< GregorianDate.js */
6820 /*
6821  * GregorianDate.js - Represent a date in the Gregorian calendar
6822  * 
6823  * Copyright © 2012-2015, JEDLSoft
6824  *
6825  * Licensed under the Apache License, Version 2.0 (the "License");
6826  * you may not use this file except in compliance with the License.
6827  * You may obtain a copy of the License at
6828  *
6829  *     http://www.apache.org/licenses/LICENSE-2.0
6830  *
6831  * Unless required by applicable law or agreed to in writing, software
6832  * distributed under the License is distributed on an "AS IS" BASIS,
6833  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
6834  *
6835  * See the License for the specific language governing permissions and
6836  * limitations under the License.
6837  */
6838 
6839 /* !depends 
6840 ilib.js
6841 IDate.js 
6842 GregorianCal.js 
6843 SearchUtils.js
6844 MathUtils.js
6845 Locale.js
6846 LocaleInfo.js 
6847 JulianDay.js
6848 GregRataDie.js
6849 TimeZone.js
6850 */
6851 
6852 
6853 
6854 
6855 /**
6856  * @class
6857  * Construct a new Gregorian date object. The constructor parameters can 
6858  * contain any of the following properties:
6859  * 
6860  * <ul>
6861  * <li><i>unixtime<i> - sets the time of this instance according to the given 
6862  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970.
6863  * 
6864  * <li><i>julianday</i> - sets the time of this instance according to the given
6865  * Julian Day instance or the Julian Day given as a float
6866  * 
6867  * <li><i>year</i> - any integer, including 0
6868  * 
6869  * <li><i>month</i> - 1 to 12, where 1 means January, 2 means February, etc.
6870  * 
6871  * <li><i>day</i> - 1 to 31
6872  * 
6873  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
6874  * is always done with an unambiguous 24 hour representation
6875  * 
6876  * <li><i>minute</i> - 0 to 59
6877  * 
6878  * <li><i>second</i> - 0 to 59
6879  * 
6880  * <li><i>millisecond</i> - 0 to 999
6881  * 
6882  * <li><i>dst</i> - boolean used to specify whether the given time components are
6883  * intended to be in daylight time or not. This is only used in the overlap
6884  * time when transitioning from DST to standard time, and the time components are 
6885  * ambiguous. Otherwise at all other times of the year, this flag is ignored.
6886  * If you specify the date using unix time (UTC) or a julian day, then the time is
6887  * already unambiguous and this flag does not need to be specified.
6888  * <p>
6889  * For example, in the US, the transition out of daylight savings time 
6890  * in 2014 happens at Nov 2, 2014 2:00am Daylight Time, when the time falls 
6891  * back to Nov 2, 2014 1:00am Standard Time. If you give a date/time components as 
6892  * "Nov 2, 2014 1:30am", then there are two 1:30am times in that day, and you would 
6893  * have to give the standard flag to indicate which of those two you mean. 
6894  * (dst=true means daylight time, dst=false means standard time).   
6895  * 
6896  * <li><i>timezone</i> - the TimeZone instance or time zone name as a string 
6897  * of this gregorian date. The date/time is kept in the local time. The time zone
6898  * is used later if this date is formatted according to a different time zone and
6899  * the difference has to be calculated, or when the date format has a time zone
6900  * component in it.
6901  * 
6902  * <li><i>locale</i> - locale for this gregorian date. If the time zone is not 
6903  * given, it can be inferred from this locale. For locales that span multiple
6904  * time zones, the one with the largest population is chosen as the one that 
6905  * represents the locale.
6906  * 
6907  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
6908  * </ul>
6909  *
6910  * If the constructor is called with another Gregorian date instance instead of
6911  * a parameter block, the other instance acts as a parameter block and its
6912  * settings are copied into the current instance.<p>
6913  * 
6914  * If the constructor is called with no arguments at all or if none of the 
6915  * properties listed above 
6916  * from <i>unixtime</i> through <i>millisecond</i> are present, then the date 
6917  * components are 
6918  * filled in with the current date at the time of instantiation. Note that if
6919  * you do not give the time zone when defaulting to the current time and the 
6920  * time zone for all of ilib was not set with <i>ilib.setTimeZone()</i>, then the
6921  * time zone will default to UTC ("Universal Time, Coordinated" or "Greenwich 
6922  * Mean Time").<p>
6923  * 
6924  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
6925  * specified in the params, it is assumed that they have the smallest possible
6926  * value in the range for the property (zero or one).<p>
6927  * 
6928  * 
6929  * @constructor
6930  * @extends IDate
6931  * @param {Object=} params parameters that govern the settings and behaviour of this Gregorian date
6932  */
6933 var GregorianDate = function(params) {
6934 	this.cal = new GregorianCal();
6935 	this.timezone = "local";
6936 
6937 	if (params) {
6938 		if (typeof(params.noinstance) === 'boolean' && params.noinstance) {
6939 			// for doing inheritance, so don't need to fill in the data. The inheriting class only wants the methods.
6940 			return;
6941 		}
6942 		if (params.locale) {
6943 			this.locale = (typeof(params.locale) === 'string') ? new Locale(params.locale) : params.locale;
6944 			var li = new LocaleInfo(this.locale);
6945 			this.timezone = li.getTimeZone(); 
6946 		}
6947 		if (params.timezone) {
6948 			this.timezone = params.timezone.toString();
6949 		}
6950 		
6951 		if (params.year || params.month || params.day || params.hour ||
6952 				params.minute || params.second || params.millisecond ) {
6953 			this.year = parseInt(params.year, 10) || 0;
6954 			this.month = parseInt(params.month, 10) || 1;
6955 			this.day = parseInt(params.day, 10) || 1;
6956 			this.hour = parseInt(params.hour, 10) || 0;
6957 			this.minute = parseInt(params.minute, 10) || 0;
6958 			this.second = parseInt(params.second, 10) || 0;
6959 			this.millisecond = parseInt(params.millisecond, 10) || 0;
6960 			if (typeof(params.dst) === 'boolean') {
6961 				this.dst = params.dst;
6962 			}
6963 			this.rd = this.newRd(params);
6964 			
6965 			// add the time zone offset to the rd to convert to UTC
6966 			this.offset = 0;
6967 			if (this.timezone === "local" && typeof(params.dst) === 'undefined') {
6968 				// if dst is defined, the intrinsic Date object has no way of specifying which version of a time you mean
6969 				// in the overlap time at the end of DST. Do you mean the daylight 1:30am or the standard 1:30am? In this
6970 				// case, use the ilib calculations below, which can distinguish between the two properly
6971 				var d = new Date(this.year, this.month-1, this.day, this.hour, this.minute, this.second, this.millisecond);
6972 				this.offset = -d.getTimezoneOffset() / 1440;
6973 			} else {
6974 				if (!this.tz) {
6975 					this.tz = new TimeZone({id: this.timezone});
6976 				}
6977 				// getOffsetMillis requires that this.year, this.rd, and this.dst 
6978 				// are set in order to figure out which time zone rules apply and 
6979 				// what the offset is at that point in the year
6980 				this.offset = this.tz._getOffsetMillisWallTime(this) / 86400000;
6981 			}
6982 			if (this.offset !== 0) {
6983 				this.rd = this.newRd({
6984 					rd: this.rd.getRataDie() - this.offset
6985 				});
6986 			}
6987 		}
6988 	} 
6989 
6990 	if (!this.rd) {
6991 		this.rd = this.newRd(params);
6992 		this._calcDateComponents();
6993 	}
6994 };
6995 
6996 GregorianDate.prototype = new IDate({noinstance: true});
6997 GregorianDate.prototype.parent = IDate;
6998 GregorianDate.prototype.constructor = GregorianDate;
6999 
7000 /**
7001  * Return a new RD for this date type using the given params.
7002  * @private
7003  * @param {Object=} params the parameters used to create this rata die instance
7004  * @returns {RataDie} the new RD instance for the given params
7005  */
7006 GregorianDate.prototype.newRd = function (params) {
7007 	return new GregRataDie(params);
7008 };
7009 
7010 /**
7011  * Calculates the Gregorian year for a given rd number.
7012  * @private
7013  * @static
7014  */
7015 GregorianDate._calcYear = function(rd) {
7016 	var days400,
7017 		days100,
7018 		days4,
7019 		years400,
7020 		years100,
7021 		years4,
7022 		years1,
7023 		year;
7024 
7025 	years400 = Math.floor((rd - 1) / 146097);
7026 	days400 = MathUtils.mod((rd - 1), 146097);
7027 	years100 = Math.floor(days400 / 36524);
7028 	days100 = MathUtils.mod(days400, 36524);
7029 	years4 = Math.floor(days100 / 1461);
7030 	days4 = MathUtils.mod(days100, 1461);
7031 	years1 = Math.floor(days4 / 365);
7032 	
7033 	year = 400 * years400 + 100 * years100 + 4 * years4 + years1;
7034 	if (years100 !== 4 && years1 !== 4) {
7035 		year++;
7036 	}
7037 	return year;
7038 };
7039 
7040 /**
7041  * @private
7042  */
7043 GregorianDate.prototype._calcYear = function(rd) {
7044 	return GregorianDate._calcYear(rd);
7045 };
7046 
7047 /**
7048  * Calculate the date components for the current time zone
7049  * @private
7050  */
7051 GregorianDate.prototype._calcDateComponents = function () {
7052 	if (this.timezone === "local" && this.rd.getRataDie() >= -99280837 && this.rd.getRataDie() <= 100719163) {
7053 		// console.log("using js Date to calculate offset");
7054 		// use the intrinsic JS Date object to do the tz conversion for us, which 
7055 		// guarantees that it follows the system tz database settings 
7056 		var d = new Date(this.rd.getTimeExtended());
7057 	
7058 		/**
7059 		 * Year in the Gregorian calendar.
7060 		 * @type number
7061 		 */
7062 		this.year = d.getFullYear();
7063 		
7064 		/**
7065 		 * The month number, ranging from 1 (January) to 12 (December).
7066 		 * @type number
7067 		 */
7068 		this.month = d.getMonth()+1;
7069 		
7070 		/**
7071 		 * The day of the month. This ranges from 1 to 31.
7072 		 * @type number
7073 		 */
7074 		this.day = d.getDate();
7075 		
7076 		/**
7077 		 * The hour of the day. This can be a number from 0 to 23, as times are
7078 		 * stored unambiguously in the 24-hour clock.
7079 		 * @type number
7080 		 */
7081 		this.hour = d.getHours();
7082 		
7083 		/**
7084 		 * The minute of the hours. Ranges from 0 to 59.
7085 		 * @type number
7086 		 */
7087 		this.minute = d.getMinutes();
7088 		
7089 		/**
7090 		 * The second of the minute. Ranges from 0 to 59.
7091 		 * @type number
7092 		 */
7093 		this.second = d.getSeconds();
7094 		
7095 		/**
7096 		 * The millisecond of the second. Ranges from 0 to 999.
7097 		 * @type number
7098 		 */
7099 		this.millisecond = d.getMilliseconds();
7100 		
7101 		this.offset = -d.getTimezoneOffset() / 1440;
7102 	} else {
7103 		// console.log("using ilib to calculate offset. tz is " + this.timezone);
7104 		// console.log("GregDate._calcDateComponents: date is " + JSON.stringify(this) + " parent is " + JSON.stringify(this.parent) + " and parent.parent is " + JSON.stringify(this.parent.parent));
7105 		if (typeof(this.offset) === "undefined") {
7106 			// console.log("calculating offset");
7107 			this.year = this._calcYear(this.rd.getRataDie());
7108 			
7109 			// now offset the RD by the time zone, then recalculate in case we were 
7110 			// near the year boundary
7111 			if (!this.tz) {
7112 				this.tz = new TimeZone({id: this.timezone});
7113 			}
7114 			this.offset = this.tz.getOffsetMillis(this) / 86400000;
7115 		// } else {
7116 			// console.log("offset is already defined somehow. type is " + typeof(this.offset));
7117 			// console.trace("Stack is this one");
7118 		}
7119 		// console.log("offset is " + this.offset);
7120 		var rd = this.rd.getRataDie();
7121 		if (this.offset !== 0) {
7122 			rd += this.offset;
7123 		}
7124 		this.year = this._calcYear(rd);
7125 		
7126 		var yearStartRd = this.newRd({
7127 			year: this.year,
7128 			month: 1,
7129 			day: 1,
7130 			cal: this.cal
7131 		});
7132 		
7133 		// remainder is days into the year
7134 		var remainder = rd - yearStartRd.getRataDie() + 1;
7135 		
7136 		var cumulative = GregorianCal.prototype.isLeapYear.call(this.cal, this.year) ? 
7137 			GregRataDie.cumMonthLengthsLeap : 
7138 			GregRataDie.cumMonthLengths; 
7139 		
7140 		this.month = SearchUtils.bsearch(Math.floor(remainder), cumulative);
7141 		remainder = remainder - cumulative[this.month-1];
7142 		
7143 		this.day = Math.floor(remainder);
7144 		remainder -= this.day;
7145 		// now convert to milliseconds for the rest of the calculation
7146 		remainder = Math.round(remainder * 86400000);
7147 		
7148 		this.hour = Math.floor(remainder/3600000);
7149 		remainder -= this.hour * 3600000;
7150 		
7151 		this.minute = Math.floor(remainder/60000);
7152 		remainder -= this.minute * 60000;
7153 		
7154 		this.second = Math.floor(remainder/1000);
7155 		remainder -= this.second * 1000;
7156 		
7157 		this.millisecond = Math.floor(remainder);
7158 	}
7159 };
7160 
7161 /**
7162  * Return the day of the week of this date. The day of the week is encoded
7163  * as number from 0 to 6, with 0=Sunday, 1=Monday, etc., until 6=Saturday.
7164  * 
7165  * @return {number} the day of the week
7166  */
7167 GregorianDate.prototype.getDayOfWeek = function() {
7168 	var rd = Math.floor(this.rd.getRataDie() + (this.offset || 0));
7169 	return MathUtils.mod(rd, 7);
7170 };
7171 
7172 /**
7173  * Return the ordinal day of the year. Days are counted from 1 and proceed linearly up to 
7174  * 365, regardless of months or weeks, etc. That is, January 1st is day 1, and 
7175  * December 31st is 365 in regular years, or 366 in leap years.
7176  * @return {number} the ordinal day of the year
7177  */
7178 GregorianDate.prototype.getDayOfYear = function() {
7179 	var cumulativeMap = this.cal.isLeapYear(this.year) ? 
7180 		GregRataDie.cumMonthLengthsLeap : 
7181 		GregRataDie.cumMonthLengths; 
7182 		
7183 	return cumulativeMap[this.month-1] + this.day;
7184 };
7185 
7186 /**
7187  * Return the era for this date as a number. The value for the era for Gregorian 
7188  * calendars is -1 for "before the common era" (BCE) and 1 for "the common era" (CE). 
7189  * BCE dates are any date before Jan 1, 1 CE. In the proleptic Gregorian calendar, 
7190  * there is a year 0, so any years that are negative or zero are BCE. In the Julian
7191  * calendar, there is no year 0. Instead, the calendar goes straight from year -1 to 
7192  * 1.
7193  * @return {number} 1 if this date is in the common era, -1 if it is before the 
7194  * common era 
7195  */
7196 GregorianDate.prototype.getEra = function() {
7197 	return (this.year < 1) ? -1 : 1;
7198 };
7199 
7200 /**
7201  * Return the name of the calendar that governs this date.
7202  * 
7203  * @return {string} a string giving the name of the calendar
7204  */
7205 GregorianDate.prototype.getCalendar = function() {
7206 	return "gregorian";
7207 };
7208 
7209 // register with the factory method
7210 IDate._constructors["gregorian"] = GregorianDate;
7211 
7212 
7213 /*< DateFactory.js */
7214 /*
7215  * DateFactory.js - Factory class to create the right subclasses of a date for any 
7216  * calendar or locale.
7217  * 
7218  * Copyright © 2012-2015, JEDLSoft
7219  *
7220  * Licensed under the Apache License, Version 2.0 (the "License");
7221  * you may not use this file except in compliance with the License.
7222  * You may obtain a copy of the License at
7223  *
7224  *     http://www.apache.org/licenses/LICENSE-2.0
7225  *
7226  * Unless required by applicable law or agreed to in writing, software
7227  * distributed under the License is distributed on an "AS IS" BASIS,
7228  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
7229  *
7230  * See the License for the specific language governing permissions and
7231  * limitations under the License.
7232  */
7233 
7234 /* !depends ilib.js Locale.js LocaleInfo.js JulianDay.js JSUtils.js CalendarFactory.js IDate.js GregorianDate.js*/
7235 
7236 
7237 
7238 // Statically depend on these even though we don't use them
7239 // to guarantee they are loaded into the cache already.
7240 
7241 /**
7242  * Factory method to create a new instance of a date subclass.<p>
7243  * 
7244  * The options parameter can be an object that contains the following
7245  * properties:
7246  * 
7247  * <ul>
7248  * <li><i>type</i> - specify the type/calendar of the date desired. The
7249  * list of valid values changes depending on which calendars are 
7250  * defined. When assembling your iliball.js, include those date type 
7251  * you wish to use in your program or web page, and they will register 
7252  * themselves with this factory method. The "gregorian",
7253  * and "julian" calendars are all included by default, as they are the
7254  * standard calendars for much of the world. If not specified, the type
7255  * of the date returned is the one that is appropriate for the locale.
7256  * This property may also be given as "calendar" instead of "type".
7257  * 
7258  * <li><i>onLoad</i> - a callback function to call when the date object is fully 
7259  * loaded. When the onLoad option is given, the date factory will attempt to
7260  * load any missing locale data using the ilib loader callback.
7261  * When the constructor is done (even if the data is already preassembled), the 
7262  * onLoad function is called with the current instance as a parameter, so this
7263  * callback can be used with preassembled or dynamic loading or a mix of the two.
7264  * 
7265  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
7266  * asynchronously. If this option is given as "false", then the "onLoad"
7267  * callback must be given, as the instance returned from this constructor will
7268  * not be usable for a while.
7269  *  
7270  * <li><i>loadParams</i> - an object containing parameters to pass to the 
7271  * loader callback function when locale data is missing. The parameters are not
7272  * interpretted or modified in any way. They are simply passed along. The object 
7273  * may contain any property/value pairs as long as the calling code is in
7274  * agreement with the loader callback function as to what those parameters mean.
7275  * </ul>
7276  * 
7277  * The options object is also passed down to the date constructor, and 
7278  * thus can contain the the properties as the date object being instantiated.
7279  * See the documentation for {@link GregorianDate}, and other
7280  * subclasses for more details on other parameter that may be passed in.<p>
7281  * 
7282  * Please note that if you do not give the type parameter, this factory
7283  * method will create a date object that is appropriate for the calendar
7284  * that is most commonly used in the specified or current ilib locale. 
7285  * For example, in Thailand, the most common calendar is the Thai solar 
7286  * calendar. If the current locale is "th-TH" (Thai for Thailand) and you 
7287  * use this factory method to construct a new date without specifying the
7288  * type, it will automatically give you back an instance of 
7289  * {@link ThaiSolarDate}. This is convenient because you do not 
7290  * need to know which locales use which types of dates. In fact, you 
7291  * should always use this factory method to make new date instances unless
7292  * you know that you specifically need a date in a particular calendar.<p>
7293  * 
7294  * Also note that when you pass in the date components such as year, month,
7295  * day, etc., these components should be appropriate for the given date
7296  * being instantiated. That is, in our Thai example in the previous
7297  * paragraph, the year and such should be given as a Thai solar year, not
7298  * the Gregorian year that you get from the Javascript Date class. In
7299  * order to initialize a date instance when you don't know what subclass
7300  * will be instantiated for the locale, use a parameter such as "unixtime" 
7301  * or "julianday" which are unambiguous and based on UTC time, instead of
7302  * the year/month/date date components. The date components for that UTC 
7303  * time will be calculated and the time zone offset will be automatically 
7304  * factored in.
7305  * 
7306  * @static
7307  * @param {Object=} options options controlling the construction of this instance, or
7308  * undefined to use the default options
7309  * @return {IDate} an instance of a calendar object of the appropriate type 
7310  */
7311 var DateFactory = function(options) {
7312 	var locale,
7313 		type,
7314 		cons,
7315 		sync = true,
7316 		obj;
7317 
7318 	if (options) {
7319 		if (options.locale) {
7320 			locale = (typeof(options.locale) === 'string') ? new Locale(options.locale) : options.locale;
7321 		}
7322 		
7323 		type = options.type || options.calendar;
7324 		
7325 		if (typeof(options.sync) === 'boolean') {
7326 			sync = options.sync;
7327 		}
7328 	}
7329 	
7330 	if (!locale) {
7331 		locale = new Locale();	// default locale
7332 	}
7333 
7334 	if (!type) {
7335 		new LocaleInfo(locale, {
7336 			sync: sync,
7337 			loadParams: options && options.loadParams,
7338 			onLoad: ilib.bind(this, function(info) {
7339 				type = info.getCalendar();
7340 				
7341 				obj = DateFactory._init(type, options);
7342 				
7343 				if (options && typeof(options.onLoad) === 'function') {
7344 					options.onLoad(obj);
7345 				}
7346 			})
7347 		});
7348 	} else {
7349 		obj = DateFactory._init(type, options);
7350 	}
7351 	
7352 	return obj
7353 };
7354 
7355 /**
7356  * Map calendar names to classes to initialize in the dynamic code model.
7357  * TODO: Need to figure out some way that this doesn't have to be updated by hand.
7358  * @private
7359  */
7360 DateFactory._dynMap = {
7361 	"coptic":       "Coptic",
7362 	"ethiopic":     "Ethiopic",
7363 	"gregorian":    "Gregorian",
7364 	"han":          "Han",
7365 	"hebrew":       "Hebrew",
7366 	"islamic":      "Islamic",
7367 	"julian":       "Julian",
7368 	"persian":      "Persian",
7369 	"persian-algo": "PersianAlgo",
7370 	"thaisolar":    "ThaiSolar"
7371 };
7372 
7373 /**
7374  * Dynamically load the code for a calendar and calendar class if necessary.
7375  * @protected
7376  */
7377 DateFactory._dynLoadDate = function (name) {
7378 	if (!IDate._constructors[name]) {
7379 		var entry = DateFactory._dynMap[name];
7380 		if (entry) {
7381 			IDate._constructors[name] = require("./" + entry + "Date.js");
7382 		}
7383 	}
7384 	return IDate._constructors[name];
7385 };
7386 
7387 /** 
7388  * @protected
7389  * @static 
7390  */
7391 DateFactory._init = function(type, options) {
7392 	var cons;
7393 	
7394 	if (ilib.isDynCode()) {
7395 		DateFactory._dynLoadDate(type);
7396 		CalendarFactory._dynLoadCalendar(type);
7397 	}
7398 	
7399 	cons = IDate._constructors[type];
7400 	
7401 	// pass the same options through to the constructor so the subclass
7402 	// has the ability to do something with if it needs to
7403 	return cons && new cons(options);
7404 };
7405 
7406 /**
7407  * Convert JavaScript Date objects and other types into native Dates. This accepts any
7408  * string or number that can be translated by the JavaScript Date class,
7409  * (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse)
7410  * any JavaScript Date classed object, any IDate subclass, an JulianDay object, an object
7411  * containing the normal options to initialize an IDate instance, or null (will 
7412  * return null or undefined if input is null or undefined). Normal output is 
7413  * a standard native subclass of the IDate object as appropriate for the locale.
7414  * 
7415  * @static
7416  * @protected
7417  * @param {IDate|Object|JulianDay|Date|string|number=} inDate The input date object, string or Number.
7418  * @param {IString|string=} timezone timezone to use if a new date object is created
7419  * @param {Locale|string=} locale locale to use when constructing an IDate
7420  * @return {IDate|null|undefined} an IDate subclass equivalent to the given inDate
7421  */
7422 DateFactory._dateToIlib = function(inDate, timezone, locale) {
7423 	if (typeof(inDate) === 'undefined' || inDate === null) {
7424 		return inDate;
7425 	}
7426 	if (inDate instanceof IDate) {
7427 		return inDate;
7428 	}
7429 	if (typeof(inDate) === 'number') {
7430 		return DateFactory({
7431 			unixtime: inDate,
7432 			timezone: timezone,
7433 			locale: locale
7434 		});
7435 	}
7436 	if (typeof(inDate) === 'string') {
7437 		inDate = new Date(inDate);
7438 	}
7439 	if (JSUtils.isDate(inDate)) {
7440 		return DateFactory({
7441 			unixtime: inDate.getTime(),
7442 			timezone: timezone,
7443 			locale: locale
7444 		});
7445 	}
7446 	if (inDate instanceof JulianDay) {
7447 		return DateFactory({
7448 			jd: inDate,
7449 			timezone: timezone,
7450 			locale: locale
7451 		});
7452 	}
7453 	if (typeof(inDate) === 'object') {
7454 		return DateFactory(inDate);
7455 	}
7456 	return DateFactory({
7457 		unixtime: inDate.getTime(),
7458 		timezone: timezone,
7459 		locale: locale
7460 	});
7461 };
7462 
7463 
7464 /*< ResBundle.js */
7465 /*
7466  * ResBundle.js - Resource bundle definition
7467  * 
7468  * Copyright © 2012-2015, JEDLSoft
7469  *
7470  * Licensed under the Apache License, Version 2.0 (the "License");
7471  * you may not use this file except in compliance with the License.
7472  * You may obtain a copy of the License at
7473  *
7474  *     http://www.apache.org/licenses/LICENSE-2.0
7475  *
7476  * Unless required by applicable law or agreed to in writing, software
7477  * distributed under the License is distributed on an "AS IS" BASIS,
7478  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
7479  *
7480  * See the License for the specific language governing permissions and
7481  * limitations under the License.
7482  */
7483 
7484 // !depends ilib.js Locale.js LocaleInfo.js IString.js Utils.js JSUtils.js
7485 
7486 // !data pseudomap
7487 
7488 
7489 
7490 
7491 /**
7492  * @class
7493  * Create a new resource bundle instance. The resource bundle loads strings
7494  * appropriate for a particular locale and provides them via the getString 
7495  * method.<p>
7496  * 
7497  * The options object may contain any (or none) of the following properties:
7498  * 
7499  * <ul>
7500  * <li><i>locale</i> - The locale of the strings to load. If not specified, the default
7501  * locale is the the default for the web page or app in which the bundle is 
7502  * being loaded.
7503  * 
7504  * <li><i>name</i> - Base name of the resource bundle to load. If not specified the default
7505  * base name is "resources".
7506  * 
7507  * <li><i>type</i> - Name the type of strings this bundle contains. Valid values are 
7508  * "xml", "html", "text", or "raw". The default is "text". If the type is "xml" or "html",
7509  * then XML/HTML entities and tags are not pseudo-translated. During a real translation, 
7510  * HTML character entities are translated to their corresponding characters in a source
7511  * string before looking that string up in the translations. Also, the characters "<", ">",
7512  * and "&" are converted to entities again in the output, but characters are left as they
7513  * are. If the type is "xml", "html", or "text" types, then the replacement parameter names
7514  * are not pseudo-translated as well so that the output can be used for formatting with 
7515  * the IString class. If the type is raw, all characters are pseudo-translated, 
7516  * including replacement parameters as well as XML/HTML tags and entities.
7517  * 
7518  * <li><i>lengthen</i> - when pseudo-translating the string, tell whether or not to 
7519  * automatically lengthen the string to simulate "long" languages such as German
7520  * or French. This is a boolean value. Default is false.
7521  * 
7522  * <li><i>missing</i> - what to do when a resource is missing. The choices are:
7523  * <ul>
7524  *   <li><i>source</i> - return the source string unchanged
7525  *   <li><i>pseudo</i> - return the pseudo-translated source string, translated to the
7526  *   script of the locale if the mapping is available, or just the default Latin 
7527  *   pseudo-translation if not
7528  *   <li><i>empty</i> - return the empty string 
7529  * </ul>
7530  * The default behaviour is the same as before, which is to return the source string
7531  * unchanged.
7532  * 
7533  * <li><i>onLoad</i> - a callback function to call when the resources are fully 
7534  * loaded. When the onLoad option is given, this class will attempt to
7535  * load any missing locale data using the ilib loader callback.
7536  * When the constructor is done (even if the data is already preassembled), the 
7537  * onLoad function is called with the current instance as a parameter, so this
7538  * callback can be used with preassembled or dynamic loading or a mix of the two. 
7539  * 
7540  * <li>sync - tell whether to load any missing locale data synchronously or 
7541  * asynchronously. If this option is given as "false", then the "onLoad"
7542  * callback must be given, as the instance returned from this constructor will
7543  * not be usable for a while. 
7544  *
7545  * <li><i>loadParams</i> - an object containing parameters to pass to the 
7546  * loader callback function when locale data is missing. The parameters are not
7547  * interpretted or modified in any way. They are simply passed along. The object 
7548  * may contain any property/value pairs as long as the calling code is in
7549  * agreement with the loader callback function as to what those parameters mean.
7550  * </ul>
7551  * 
7552  * The locale option may be given as a locale spec string or as an 
7553  * Locale object. If the locale option is not specified, then strings for
7554  * the default locale will be loaded.<p> 
7555  * 
7556  * The name option can be used to put groups of strings together in a
7557  * single bundle. The strings will then appear together in a JS object in
7558  * a JS file that can be included before the ilib.<p>
7559  * 
7560  * A resource bundle with a particular name is actually a set of bundles
7561  * that are each specific to a language, a language plus a region, etc. 
7562  * All bundles with the same base name should
7563  * contain the same set of source strings, but with different translations for 
7564  * the given locale. The user of the bundle does not need to be aware of 
7565  * the locale of the bundle, as long as it contains values for the strings 
7566  * it needs.<p>
7567  * 
7568  * Strings in bundles for a particular locale are inherited from parent bundles
7569  * that are more generic. In general, the hierarchy is as follows (from 
7570  * least locale-specific to most locale-specific):
7571  * 
7572  * <ol>
7573  * <li> language
7574  * <li> region
7575  * <li> language_script
7576  * <li> language_region
7577  * <li> region_variant
7578  * <li> language_script_region
7579  * <li> language_region_variant
7580  * <li> language_script_region_variant
7581  * </ol>
7582  * 
7583  * That is, if the translation for a string does not exist in the current
7584  * locale, the more-generic parent locale is searched for the string. In the
7585  * worst case scenario, the string is not found in the base locale's strings. 
7586  * In this case, the missing option guides this class on what to do. If
7587  * the missing option is "source", then the original source is returned as 
7588  * the translation. If it is "empty", the empty string is returned. If it
7589  * is "pseudo", then the pseudo-translated string that is appropriate for
7590  * the default script of the locale is returned.<p> 
7591  * 
7592  * This allows developers to create code with new or changed strings in it and check in that
7593  * code without waiting for the translations to be done first. The translated
7594  * version of the app or web site will still function properly, but will show 
7595  * a spurious untranslated string here and there until the translations are 
7596  * done and also checked in.<p>   
7597  *  
7598  * The base is whatever language your developers use to code in. For
7599  * a German web site, strings in the source code may be written in German 
7600  * for example. Often this base is English, as many web sites are coded in
7601  * English, but that is not required.<p>
7602  * 
7603  * The strings can be extracted with the ilib localization tool (which will be
7604  * shipped at some future time.) Once the strings
7605  * have been translated, the set of translated files can be generated with the
7606  * same tool. The output from the tool can be used as input to the ResBundle
7607  * object. It is up to the web page or app to make sure the JS file that defines
7608  * the bundle is included before creating the ResBundle instance.<p>
7609  * 
7610  * A special locale "zxx-XX" is used as the pseudo-translation locale because
7611  * zxx means "no linguistic information" in the ISO 639 standard, and the region 
7612  * code XX is defined to be user-defined in the ISO 3166 standard. 
7613  * Pseudo-translation is a locale where the translations are generated on
7614  * the fly based on the contents of the source string. Characters in the source 
7615  * string are replaced with other characters and returned. 
7616  * 
7617  * Example. If the source string is:
7618  * 
7619  * <pre>
7620  * "This is a string"
7621  * </pre>
7622  * 
7623  * then the pseudo-translated version might look something like this: 
7624  * 
7625  * <pre>
7626  * "Ţħïş ïş á şţřïñĝ"
7627  * </pre>
7628  * <p>
7629  * 
7630  * Pseudo-translation can be used to test that your app or web site is translatable
7631  * before an actual translation has happened. These bugs can then be fixed 
7632  * before the translation starts, avoiding an explosion of bugs later when
7633  * each language's tester registers the same bug complaining that the same 
7634  * string is not translated. When pseudo-localizing with
7635  * the Latin script, this allows the strings to be readable in the UI in the 
7636  * source language (if somewhat funky-looking), 
7637  * so that a tester can easily verify that the string is properly externalized 
7638  * and loaded from a resource bundle without the need to be able to read a
7639  * foreign language.<p> 
7640  * 
7641  * If one of a list of script tags is given in the pseudo-locale specifier, then the
7642  * pseudo-localization can map characters to very rough transliterations of
7643  * characters in the given script. For example, zxx-Hebr-XX maps strings to
7644  * Hebrew characters, which can be used to test your UI in a right-to-left
7645  * language to catch bidi bugs before a translation is done. Currently, the
7646  * list of target scripts includes Hebrew (Hebr), Chinese Simplified Han (Hans),
7647  * and Cyrillic (Cyrl) with more to be added later. If no script is explicitly
7648  * specified in the locale spec, or if the script is not supported,
7649  * then the default mapping maps Latin base characters to accented versions of
7650  * those Latin characters as in the example above.
7651  *  
7652  * When the "lengthen" property is set to true in the options, the 
7653  * pseudotranslation code will add digits to the end of the string to simulate
7654  * the lengthening that occurs when translating to other languages. The above 
7655  * example will come out like this:
7656  * 
7657  * <pre>
7658  * "Ţħïş ïş á şţřïñĝ76543210"
7659  * </pre>
7660  * 
7661  * The string is lengthened according to the length of the source string. If
7662  * the source string is less than 20 characters long, the string is lengthened 
7663  * by 50%. If the source string is 20-40 
7664  * characters long, the string is lengthened by 33%. If te string is greater
7665  * than 40 characters long, the string is lengthened by 20%.<p>
7666  * 
7667  * The pseudotranslation always ends a string with the digit "0". If you do
7668  * not see the digit "0" in the UI for your app, you know that truncation
7669  * has occurred, and the number you see at the end of the string tells you 
7670  * how many characters were truncated.<p>
7671  * 
7672  * 
7673  * @constructor
7674  * @param {?Object} options Options controlling how the bundle is created
7675  */
7676 var ResBundle = function (options) {
7677 	var lookupLocale, spec;
7678 	
7679 	this.locale = new Locale();	// use the default locale
7680 	this.baseName = "strings";
7681 	this.type = "text";
7682 	this.loadParams = {};
7683 	this.missing = "source";
7684 	this.sync = true;
7685 	
7686 	if (options) {
7687 		if (options.locale) {
7688 			this.locale = (typeof(options.locale) === 'string') ? 
7689 					new Locale(options.locale) :
7690 					options.locale;
7691 		}
7692 		if (options.name) {
7693 			this.baseName = options.name;
7694 		}
7695 		if (options.type) {
7696 			this.type = options.type;
7697 		}
7698 		this.lengthen = options.lengthen || false;
7699 		
7700 		if (typeof(options.sync) !== 'undefined') {
7701 			this.sync = (options.sync == true);
7702 		}
7703 		
7704 		if (typeof(options.loadParams) !== 'undefined') {
7705 			this.loadParams = options.loadParams;
7706 		}
7707 		if (typeof(options.missing) !== 'undefined') {
7708 			if (options.missing === "pseudo" || options.missing === "empty") {
7709 				this.missing = options.missing;
7710 			}
7711 		}
7712 	} else {
7713 		options = {};
7714 	}
7715 	
7716 	this.map = {};
7717 
7718 	if (!ResBundle[this.baseName]) {
7719 		ResBundle[this.baseName] = {};
7720 	}
7721 
7722 	lookupLocale = this.locale.isPseudo() ? new Locale("en-US") : this.locale;
7723 
7724 	Utils.loadData({
7725 		object: ResBundle[this.baseName], 
7726 		locale: lookupLocale, 
7727 		name: this.baseName + ".json", 
7728 		sync: this.sync, 
7729 		loadParams: this.loadParams, 
7730 		callback: ilib.bind(this, function (map) {
7731 			if (!map) {
7732 				map = ilib.data[this.baseName] || {};
7733 				spec = lookupLocale.getSpec().replace(/-/g, '_');
7734 				ResBundle[this.baseName].cache[spec] = map;
7735 			}
7736 			this.map = map;
7737 			if (this.locale.isPseudo()) {
7738 				if (!ResBundle.pseudomap) {
7739 					ResBundle.pseudomap = {};
7740 				}
7741 	
7742 				this._loadPseudo(this.locale, options.onLoad);
7743 			} else if (this.missing === "pseudo") {
7744 				if (!ResBundle.pseudomap) {
7745 					ResBundle.pseudomap = {};
7746 				}
7747 	
7748 				new LocaleInfo(this.locale, {
7749 					sync: this.sync,
7750 					loadParams: this.loadParams,
7751 					onLoad: ilib.bind(this, function (li) {
7752 						var pseudoLocale = new Locale("zxx", "XX", undefined, li.getDefaultScript());
7753 						this._loadPseudo(pseudoLocale, options.onLoad);
7754 					})
7755 				});
7756 			} else {
7757 				if (typeof(options.onLoad) === 'function') {
7758 					options.onLoad(this);
7759 				}
7760 			}
7761 		})
7762 	});
7763 
7764 	// console.log("Merged resources " + this.locale.toString() + " are: " + JSON.stringify(this.map));
7765 	//if (!this.locale.isPseudo() && JSUtils.isEmpty(this.map)) {
7766 	//	console.log("Resources for bundle " + this.baseName + " locale " + this.locale.toString() + " are not available.");
7767 	//}
7768 };
7769 
7770 ResBundle.defaultPseudo = ilib.data.pseudomap || {
7771 	"a": "à",
7772 	"e": "ë",
7773 	"i": "í",
7774 	"o": "õ",
7775 	"u": "ü",
7776 	"y": "ÿ",
7777 	"A": "Ã",
7778 	"E": "Ë",
7779 	"I": "Ï",
7780 	"O": "Ø",
7781 	"U": "Ú",
7782 	"Y": "Ŷ"
7783 };
7784 
7785 ResBundle.prototype = {
7786     /**
7787      * @protected
7788      */
7789     _loadPseudo: function (pseudoLocale, onLoad) {
7790 		Utils.loadData({
7791 			object: ResBundle.pseudomap, 
7792 			locale: pseudoLocale, 
7793 			name: "pseudomap.json", 
7794 			sync: this.sync, 
7795 			loadParams: this.loadParams, 
7796 			callback: ilib.bind(this, function (map) {
7797 				if (!map || JSUtils.isEmpty(map)) {
7798 					map = ResBundle.defaultPseudo;
7799 					var spec = pseudoLocale.getSpec().replace(/-/g, '_');
7800 					ResBundle.pseudomap.cache[spec] = map;
7801 				}
7802 				this.pseudomap = map;
7803 				if (typeof(onLoad) === 'function') {
7804 					onLoad(this);
7805 				}	
7806 			})
7807 		});
7808     },
7809     
7810 	/**
7811 	 * Return the locale of this resource bundle.
7812 	 * @return {Locale} the locale of this resource bundle object 
7813 	 */
7814 	getLocale: function () {
7815 		return this.locale;
7816 	},
7817 	
7818 	/**
7819 	 * Return the name of this resource bundle. This corresponds to the name option
7820 	 * given to the constructor.
7821 	 * @return {string} name of the the current instance
7822 	 */
7823 	getName: function () {
7824 		return this.baseName;
7825 	},
7826 	
7827 	/**
7828 	 * Return the type of this resource bundle. This corresponds to the type option
7829 	 * given to the constructor.
7830 	 * @return {string} type of the the current instance
7831 	 */
7832 	getType: function () {
7833 		return this.type;
7834 	},
7835 
7836 	/**
7837 	 * @private
7838 	 * Pseudo-translate a string
7839 	 */
7840 	_pseudo: function (str) {
7841 		if (!str) {
7842 			return undefined;
7843 		}
7844 		var ret = "", i;
7845 		for (i = 0; i < str.length; i++) {
7846 			if (this.type !== "raw") {
7847 				if (this.type === "html" || this.type === "xml") {
7848 					if (str.charAt(i) === '<') {
7849 						ret += str.charAt(i++);
7850 						while (i < str.length && str.charAt(i) !== '>') {
7851 							ret += str.charAt(i++);
7852 						}
7853 						if (i < str.length) {
7854 							ret += str.charAt(i++);
7855 						}
7856 					} else if (str.charAt(i) === '&') {
7857 						ret += str.charAt(i++);
7858 						while (i < str.length && str.charAt(i) !== ';' && str.charAt(i) !== ' ') {
7859 							ret += str.charAt(i++);
7860 						}
7861 						if (i < str.length) {
7862 							ret += str.charAt(i++);
7863 						}
7864 					}
7865 				}
7866 				if (i < str.length) { 
7867 					if (str.charAt(i) === '{') {
7868 						ret += str.charAt(i++);
7869 						while (i < str.length && str.charAt(i) !== '}') {
7870 							ret += str.charAt(i++);
7871 						}
7872 						if (i < str.length) {
7873 							ret += str.charAt(i);
7874 						}
7875 					} else {
7876 						ret += this.pseudomap[str.charAt(i)] || str.charAt(i);
7877 					}
7878 				}
7879 			} else {
7880 				ret += this.pseudomap[str.charAt(i)] || str.charAt(i);
7881 			}
7882 		}
7883 		if (this.lengthen) {
7884 			var add;
7885 			if (ret.length <= 20) {
7886 				add = Math.round(ret.length / 2);
7887 			} else if (ret.length > 20 && ret.length <= 40) {
7888 				add = Math.round(ret.length / 3);
7889 			} else {
7890 				add = Math.round(ret.length / 5);
7891 			}
7892 			for (i = add-1; i >= 0; i--) {
7893 				ret += (i % 10);
7894 			}
7895 		}
7896 		if (this.locale.getScript() === "Hans" || this.locale.getScript() === "Hant" ||
7897 				this.locale.getScript() === "Hani" ||
7898 				this.locale.getScript() === "Hrkt" || this.locale.getScript() === "Jpan" ||
7899 				this.locale.getScript() === "Hira" || this.locale.getScript() === "Kana" ) {
7900 			// simulate Asian languages by getting rid of all the spaces
7901 			ret = ret.replace(/ /g, "");
7902 		}
7903 		return ret;
7904 	},
7905 	
7906 	/**
7907 	 * @private
7908 	 * Escape html characters in the output.
7909 	 */
7910 	_escapeXml: function (str) {
7911 		str = str.replace(/&/g, '&');
7912 		str = str.replace(/</g, '<');
7913 		str = str.replace(/>/g, '>');
7914 		return str;
7915 	},
7916 
7917 	/**
7918 	 * @private
7919 	 * @param {string} str the string to unescape
7920 	 */
7921 	_unescapeXml: function (str) {
7922 		str = str.replace(/&/g, '&');
7923 		str = str.replace(/</g, '<');
7924 		str = str.replace(/>/g, '>');
7925 		return str;
7926 	},
7927 	
7928 	/**
7929 	 * @private
7930 	 * Create a key name out of a source string. All this does so far is 
7931 	 * compress sequences of white space into a single space on the assumption
7932 	 * that this doesn't really change the meaning of the string, and therefore
7933 	 * all such strings that compress to the same thing should share the same
7934 	 * translation.
7935 	 * @param {null|string=} source the source string to make a key out of
7936 	 */
7937 	_makeKey: function (source) {
7938 		if (!source) return undefined;
7939 		var key = source.replace(/\s+/gm, ' ');
7940 		return (this.type === "xml" || this.type === "html") ? this._unescapeXml(key) : key;
7941 	},
7942 	
7943 	/**
7944 	 * Return a localized string. If the string is not found in the loaded set of
7945 	 * resources, the original source string is returned. If the key is not given,
7946 	 * then the source string itself is used as the key. In the case where the 
7947 	 * source string is used as the key, the whitespace is compressed down to 1 space
7948 	 * each, and the whitespace at the beginning and end of the string is trimmed.<p>
7949 	 * 
7950 	 * The escape mode specifies what type of output you are escaping the returned
7951 	 * string for. Modes are similar to the types: 
7952 	 * 
7953 	 * <ul>
7954 	 * <li>"html" -- prevents HTML injection by escaping the characters < > and &
7955 	 * <li>"xml" -- currently same as "html" mode
7956 	 * <li>"js" -- prevents breaking Javascript syntax by backslash escaping all quote and 
7957 	 * double-quote characters
7958 	 * <li>"attribute" -- meant for HTML attribute values. Currently this is the same as
7959 	 * "js" escape mode.
7960 	 * <li>"default" -- use the type parameter from the constructor as the escape mode as well
7961 	 * <li>"none" or undefined -- no escaping at all.
7962 	 * </ul>
7963 	 * 
7964 	 * The type parameter of the constructor specifies what type of strings this bundle
7965 	 * is operating upon. This allows pseudo-translation and automatic key generation
7966 	 * to happen properly by telling this class how to parse the string. The escape mode 
7967 	 * for this method is different in that it specifies how this string will be used in 
7968 	 * the calling code and therefore how to escape it properly.<p> 
7969 	 * 
7970 	 * For example, a section of Javascript code may be constructing an HTML snippet in a 
7971 	 * string to add to the web page. In this case, the type parameter in the constructor should
7972 	 * be "html" so that the source string can be parsed properly, but the escape mode should
7973 	 * be "js" so that the output string can be used in Javascript without causing syntax
7974 	 * errors.
7975 	 * 
7976 	 * @param {?string=} source the source string to translate
7977 	 * @param {?string=} key optional name of the key, if any
7978 	 * @param {?string=} escapeMode escape mode, if any
7979 	 * @return {IString|undefined} the translation of the given source/key or undefined 
7980 	 * if the translation is not found and the source is undefined 
7981 	 */
7982 	getString: function (source, key, escapeMode) {
7983 		if (!source && !key) return new IString("");
7984 
7985 		var trans;
7986 		if (this.locale.isPseudo()) {
7987 			var str = source ? source : this.map[key];
7988 			trans = this._pseudo(str || key);
7989 		} else {
7990 			var keyName = key || this._makeKey(source);
7991 			if (typeof(this.map[keyName]) !== 'undefined') {
7992 				trans = this.map[keyName];
7993 			} else if (this.missing === "pseudo") {
7994 				trans = this._pseudo(source || key);
7995 			} else if (this.missing === "empty") {
7996 				trans = "";
7997 			} else {
7998 				trans = source;
7999 			}
8000 		}
8001 
8002 		if (escapeMode && escapeMode !== "none") {
8003 			if (escapeMode == "default") {
8004 				escapeMode = this.type;
8005 			}
8006 			if (escapeMode === "xml" || escapeMode === "html") {
8007 				trans = this._escapeXml(trans);
8008 			} else if (escapeMode == "js" || escapeMode === "attribute") {
8009 				trans = trans.replace(/'/g, "\\\'").replace(/"/g, "\\\"");
8010 			}
8011 		}
8012 		if (trans === undefined) {
8013 			return undefined;
8014 		} else {
8015 			var ret = new IString(trans);
8016 			ret.setLocale(this.locale.getSpec(), true, this.loadParams); // no callback
8017 			return ret;
8018 		}
8019 	},
8020 	
8021 	/**
8022 	 * Return a localized string as a Javascript object. This does the same thing as
8023 	 * the getString() method, but it returns a regular Javascript string instead of
8024 	 * and IString instance. This means it cannot be formatted with the format()
8025 	 * method without being wrapped in an IString instance first.
8026 	 * 
8027 	 * @param {?string=} source the source string to translate
8028 	 * @param {?string=} key optional name of the key, if any
8029 	 * @param {?string=} escapeMode escape mode, if any
8030 	 * @return {string|undefined} the translation of the given source/key or undefined 
8031 	 * if the translation is not found and the source is undefined
8032 	 */
8033 	getStringJS: function(source, key, escapeMode) {
8034 		return this.getString(source, key, escapeMode).toString();
8035 	},
8036 	
8037 	/**
8038 	 * Return true if the current bundle contains a translation for the given key and
8039 	 * source. The
8040 	 * getString method will always return a string for any given key and source 
8041 	 * combination, so it cannot be used to tell if a translation exists. Either one
8042 	 * or both of the source and key must be specified. If both are not specified,
8043 	 * this method will return false.
8044 	 * 
8045 	 * @param {?string=} source source string to look up
8046 	 * @param {?string=} key key to look up
8047 	 * @return {boolean} true if this bundle contains a translation for the key, and 
8048 	 * false otherwise
8049 	 */
8050 	containsKey: function(source, key) {
8051 		if (typeof(source) === 'undefined' && typeof(key) === 'undefined') {
8052 			return false;
8053 		}
8054 		
8055 		var keyName = key || this._makeKey(source);
8056 		return typeof(this.map[keyName]) !== 'undefined';
8057 	},
8058 	
8059 	/**
8060 	 * Return the merged resources as an entire object. When loading resources for a
8061 	 * locale that are not just a set of translated strings, but instead an entire 
8062 	 * structured javascript object, you can gain access to that object via this call. This method
8063 	 * will ensure that all the of the parts of the object are correct for the locale.<p>
8064 	 * 
8065 	 * For pre-assembled data, it starts by loading <i>ilib.data[name]</i>, where 
8066 	 * <i>name</i> is the base name for this set of resources. Then, it successively 
8067 	 * merges objects in the base data using progressively more locale-specific data. 
8068 	 * It loads it in this order from <i>ilib.data</i>:
8069 	 * 
8070 	 * <ol>
8071 	 * <li> language
8072 	 * <li> region
8073 	 * <li> language_script
8074 	 * <li> language_region
8075 	 * <li> region_variant
8076 	 * <li> language_script_region
8077 	 * <li> language_region_variant
8078 	 * <li> language_script_region_variant
8079 	 * </ol>
8080 	 * 
8081 	 * For dynamically loaded data, the code attempts to load the same sequence as
8082 	 * above, but with slash path separators instead of underscores.<p>
8083 	 *  
8084 	 * Loading the resources this way allows the program to share resources between all
8085 	 * locales that share a common language, region, or script. As a 
8086 	 * general rule-of-thumb, resources should be as generic as possible in order to
8087 	 * cover as many locales as possible.
8088 	 * 
8089 	 * @return {Object} returns the object that is the basis for this resources instance
8090 	 */
8091 	getResObj: function () {
8092 		return this.map;
8093 	}
8094 };
8095 
8096 
8097 /*< ISet.js */
8098 /*
8099  * ISet.js - ilib Set class definition for platforms older than ES6
8100  * 
8101  * Copyright © 2015, JEDLSoft
8102  *
8103  * Licensed under the Apache License, Version 2.0 (the "License");
8104  * you may not use this file except in compliance with the License.
8105  * You may obtain a copy of the License at
8106  *
8107  *     http://www.apache.org/licenses/LICENSE-2.0
8108  *
8109  * Unless required by applicable law or agreed to in writing, software
8110  * distributed under the License is distributed on an "AS IS" BASIS,
8111  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8112  *
8113  * See the License for the specific language governing permissions and
8114  * limitations under the License.
8115  */
8116 
8117 /**
8118  * Create a new set with elements in the given array. The type of
8119  * the set is gleaned from the type of the first element in the
8120  * elements array, or the first element added to the set. The type
8121  * may be "string" or "number", and all elements will be returned
8122  * as elements of that type.
8123  * 
8124  * @class
8125  * @param {Array.<string|number>} elements initial elements to add to the set
8126  * @constructor
8127  */
8128 var ISet = function(elements) {
8129 	this.elements = {};
8130 
8131 	if (elements && elements.length) {
8132 		for (var i = 0; i < elements.length; i++) {
8133 			this.elements[elements[i]] = true;
8134 		}
8135 		
8136 		this.type = typeof(elements[0]);
8137 	}
8138 };
8139 
8140 /**
8141  * @private
8142  */
8143 ISet.prototype._addOne = function(element) {
8144 	if (this.isEmpty()) {
8145 		this.type = typeof(element);
8146 	}
8147 	
8148 	if (!this.elements[element]) {
8149 		this.elements[element] = true;
8150 		return true;
8151 	}
8152 
8153 	return false;
8154 };
8155 
8156 /**
8157  * Adds the specified element or array of elements to this set if it is or they are not 
8158  * already present.
8159  * 
8160  * @param {*|Array.<*>} element element or array of elements to add
8161  * @return {boolean} true if this set did not already contain the specified element[s]
8162  */
8163 ISet.prototype.add = function(element) {
8164 	var ret = false;
8165 	
8166 	if (typeof(element) === "object") {
8167 		for (var i = 0; i < element.length; i++) {
8168 			ret = this._addOne(element[i]) || ret;
8169 		}
8170 	} else {
8171 		ret = this._addOne(element);
8172 	}
8173 	
8174 	return ret;
8175 };
8176 
8177 /**
8178  * Removes all of the elements from this set.
8179  */
8180 ISet.prototype.clear = function() {
8181 	this.elements = {};
8182 };
8183 
8184 /**
8185  * Returns true if this set contains the specified element.
8186  * @param {*} element the element to test
8187  * @return {boolean}
8188  */
8189 ISet.prototype.contains = function(element) {
8190 	return this.elements[element] || false;
8191 };
8192 
8193 /**
8194  * Returns true if this set contains no elements.
8195  * @return {boolean}
8196  */
8197 ISet.prototype.isEmpty = function() {
8198 	return (Object.keys(this.elements).length === 0);
8199 };
8200 
8201 /**
8202  * Removes the specified element from this set if it is present.
8203  * @param {*} element the element to remove
8204  * @return {boolean} true if the set contained the specified element
8205  */
8206 ISet.prototype.remove = function(element) {
8207 	if (this.elements[element]) {
8208 		delete this.elements[element];
8209 		return true;
8210 	}
8211 	
8212 	return false;
8213 };
8214 
8215 /**
8216  * Return the set as a javascript array.
8217  * @return {Array.<*>} the set represented as a javascript array
8218  */
8219 ISet.prototype.asArray = function() {
8220 	var keys = Object.keys(this.elements);
8221 	
8222 	// keys is an array of strings. Convert to numbers if necessary
8223 	if (this.type === "number") {
8224 		var tmp = [];
8225 		for (var i = 0; i < keys.length; i++) {
8226 			tmp.push(Number(keys[i]).valueOf());
8227 		}
8228 		keys = tmp;
8229 	}
8230 	
8231 	return keys;
8232 };
8233 
8234 /**
8235  * Represents the current set as json.
8236  * @return {string} the current set represented as json
8237  */
8238 ISet.prototype.toJson = function() {
8239 	return JSON.stringify(this.asArray());
8240 };
8241 
8242 /**
8243  * Convert to a javascript representation of this object.
8244  * In this case, it is a normal JS array.
8245  * @return {*} the JS representation of this object
8246  */
8247 ISet.prototype.toJS = function() {
8248 	return this.asArray();
8249 };
8250 
8251 /**
8252  * Convert from a js representation to an internal one.
8253  * @return {ISet|undefined} the current object, or undefined if the conversion did not work
8254  */
8255 ISet.prototype.fromJS = function(obj) {
8256 	return this.add(obj) ? this : undefined;
8257 };
8258 
8259 
8260 
8261 /*< DateFmt.js */
8262 /*
8263  * DateFmt.js - Date formatter definition
8264  * 
8265  * Copyright © 2012-2015, JEDLSoft
8266  *
8267  * Licensed under the Apache License, Version 2.0 (the "License");
8268  * you may not use this file except in compliance with the License.
8269  * You may obtain a copy of the License at
8270  *
8271  *     http://www.apache.org/licenses/LICENSE-2.0
8272  *
8273  * Unless required by applicable law or agreed to in writing, software
8274  * distributed under the License is distributed on an "AS IS" BASIS,
8275  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8276  *
8277  * See the License for the specific language governing permissions and
8278  * limitations under the License.
8279  */
8280 
8281 /*
8282 !depends 
8283 ilib.js 
8284 Locale.js 
8285 IDate.js
8286 DateFactory.js  
8287 IString.js 
8288 ResBundle.js 
8289 Calendar.js
8290 CalendarFactory.js
8291 LocaleInfo.js
8292 TimeZone.js
8293 GregorianCal.js
8294 JSUtils.js
8295 Utils.js
8296 ISet.js
8297 */
8298 
8299 // !data dateformats sysres
8300 
8301 
8302 
8303 
8304 
8305 
8306 /**
8307  * @class
8308  * Create a new date formatter instance. The date formatter is immutable once
8309  * it is created, but can format as many different dates as needed with the same
8310  * options. Create different date formatter instances for different purposes
8311  * and then keep them cached for use later if you have more than one date to
8312  * format.<p>
8313  * 
8314  * The options may contain any of the following properties:
8315  * 
8316  * <ul>
8317  * <li><i>locale</i> - locale to use when formatting the date/time. If the locale is
8318  * not specified, then the default locale of the app or web page will be used.
8319  * 
8320  * <li><i>calendar</i> - the type of calendar to use for this format. The value should
8321  * be a sting containing the name of the calendar. Currently, the supported
8322  * types are "gregorian", "julian", "arabic", "hebrew", or "chinese". If the
8323  * calendar is not specified, then the default calendar for the locale is used. When the
8324  * calendar type is specified, then the format method must be called with an instance of
8325  * the appropriate date type. (eg. Gregorian calendar means that the format method must 
8326  * be called with a GregDate instance.)
8327  *  
8328  * <li><i>timezone</i> - time zone to use when formatting times. This may be a time zone
8329  * instance or a time zone specifier from the IANA list of time zone database names 
8330  * (eg. "America/Los_Angeles"), 
8331  * the string "local", or a string specifying the offset in RFC 822 format. The IANA
8332  * list of time zone names can be viewed at 
8333  * <a href="http://en.wikipedia.org/wiki/List_of_tz_database_time_zones">this page</a>.
8334  * If the time zone is given as "local", the offset from UTC as given by
8335  * the Javascript system is used. If the offset is given as an RFC 822 style offset
8336  * specifier, it will parse that string and use the resulting offset. If the time zone
8337  * is not specified, the
8338  * default time zone for the locale is used. If both the date object and this formatter
8339  * instance contain time zones and those time zones are different from each other, the 
8340  * formatter will calculate the offset between the time zones and subtract it from the 
8341  * date before formatting the result for the current time zone. The theory is that a date
8342  * object that contains a time zone specifies a specific instant in time that is valid
8343  * around the world, whereas a date object without one is a local time and can only be
8344  * used for doing things in the local time zone of the user.
8345  * 
8346  * <li><i>type</i> - Specify whether this formatter should format times only, dates only, or
8347  * both times and dates together. Valid values are "time", "date", and "datetime". Note that
8348  * in some locales, the standard format uses the order "time followed by date" and in others, 
8349  * the order is exactly opposite, so it is better to create a single "datetime" formatter 
8350  * than it is to create a time formatter and a date formatter separately and concatenate the 
8351  * results. A "datetime" formatter will get the order correct for the locale.<p>
8352  * 
8353  * The default type if none is specified in with the type option is "date".
8354  * 
8355  * <li><i>length</i> - Specify the length of the format to use. The length is the approximate size of the 
8356  * formatted string.
8357  * 
8358  * <ul>
8359  * <li><i>short</i> - use a short representation of the time. This is the most compact format possible for the locale.
8360  * <li><i>medium</i> - use a medium length representation of the time. This is a slightly longer format.
8361  * <li><i>long</i> - use a long representation of the time. This is a fully specified format, but some of the textual 
8362  * components may still be abbreviated
8363  * <li><i>full</i> - use a full representation of the time. This is a fully specified format where all the textual 
8364  * components are spelled out completely
8365  * </ul>
8366  * 
8367  * eg. The "short" format for an en_US date may be "MM/dd/yy", whereas the long format might be "d MMM, yyyy". In the long
8368  * format, the month name is textual instead of numeric and is longer, the year is 4 digits instead of 2, and the format 
8369  * contains slightly more spaces and formatting characters.<p>
8370  * 
8371  * Note that the length parameter does not specify which components are to be formatted. Use the "date" and the "time"
8372  * properties to specify the components. Also, very few of the components of a time format differ according to the length,
8373  * so this property has little to no affect on time formatting.
8374  * 
8375  * <li><i>date</i> - This property tells
8376  * which components of a date format to use. For example,
8377  * sometimes you may wish to format a date that only contains the month and date
8378  * without the year, such as when displaying a person's yearly birthday. The value
8379  * of this property allows you to specify only those components you want to see in the
8380  * final output, ordered correctly for the locale. <p>
8381  * 
8382  * Valid values are:
8383  * 
8384  * <ul>
8385  * <li><i>dmwy</i> - format all components, weekday, date, month, and year
8386  * <li><i>dmy</i> - format only date, month, and year
8387  * <li><i>dmw</i> - format only weekday, date, and month
8388  * <li><i>dm</i> - format only date and month
8389  * <li><i>my</i> - format only month and year
8390  * <li><i>dw</i> - format only the weekday and date
8391  * <li><i>d</i> - format only the date
8392  * <li><i>m</i> - format only the month, in numbers for shorter lengths, and letters for 
8393  * longer lengths
8394  * <li><i>n</i> - format only the month, in letters only for all lengths
8395  * <li><i>y</i> - format only the year
8396  * </ul>
8397  * Default components, if this property is not specified, is "dmy". This property may be specified
8398  * but has no affect if the current formatter is for times only.<p>
8399  * 
8400  * As of ilib 12.0, you can now pass ICU style skeletons in this option similar to the ones you 
8401  * get from <a href="http://icu-project.org/apiref/icu4c432/classDateTimePatternGenerator.html#aa30c251609c1eea5ad60c95fc497251e">DateTimePatternGenerator.getSkeleton()</a>. 
8402  * It will not extract the length from the skeleton so you still need to pass the length property, 
8403  * but it will extract the date components.
8404  * 
8405  * <li><i>time</i> - This property gives which components of a time format to use. The time will be formatted 
8406  * correctly for the locale with only the time components requested. For example, a clock might only display 
8407  * the hour and minute and not need the seconds or the am/pm component. In this case, the time property should be set 
8408  * to "hm". <p>
8409  * 
8410  * Valid values for this property are:
8411  * 
8412  * <ul>
8413  * <li><i>ahmsz</i> - format the hours, minutes, seconds, am/pm (if using a 12 hour clock), and the time zone
8414  * <li><i>ahms</i> - format the hours, minutes, seconds, and am/pm (if using a 12 hour clock)
8415  * <li><i>hmsz</i> - format the hours, minutes, seconds, and the time zone
8416  * <li><i>hms</i> - format the hours, minutes, and seconds
8417  * <li><i>ahmz</i> - format the hours, minutes, am/pm (if using a 12 hour clock), and the time zone
8418  * <li><i>ahm</i> - format the hours, minutes, and am/pm (if using a 12 hour clock)
8419  * <li><i>hmz</i> - format the hours, minutes, and the time zone
8420  * <li><i>ah</i> - format only the hours and am/pm if using a 12 hour clock
8421  * <li><i>hm</i> - format only the hours and minutes
8422  * <li><i>ms</i> - format only the minutes and seconds
8423  * <li><i>h</i> - format only the hours
8424  * <li><i>m</i> - format only the minutes
8425  * <li><i>s</i> - format only the seconds
8426  * </ul>
8427  * 
8428  * If you want to format a length of time instead of a particular instant
8429  * in time, use the duration formatter object (DurationFmt) instead because this
8430  * formatter is geared towards instants. A date formatter will make sure that each component of the 
8431  * time is within the normal range
8432  * for that component. That is, the minutes will always be between 0 and 59, no matter
8433  * what is specified in the date to format. A duration format will allow the number
8434  * of minutes to exceed 59 if, for example, you were displaying the length of
8435  * a movie of 198 minutes.<p>
8436  * 
8437  * Default value if this property is not specified is "hma".<p>
8438  * 
8439  * As of ilib 12.0, you can now pass ICU style skeletons in this option similar to the ones you 
8440  * get from <a href="http://icu-project.org/apiref/icu4c432/classDateTimePatternGenerator.html#aa30c251609c1eea5ad60c95fc497251e">DateTimePatternGenerator.getSkeleton()</a>. 
8441  * It will not extract the length from the skeleton so you still need to pass the length property, 
8442  * but it will extract the time components.
8443  * 
8444  * <li><i>clock</i> - specify that the time formatter should use a 12 or 24 hour clock. 
8445  * Valid values are "12" and "24".<p>
8446  * 
8447  * In some locales, both clocks are used. For example, in en_US, the general populace uses
8448  * a 12 hour clock with am/pm, but in the US military or in nautical or aeronautical or 
8449  * scientific writing, it is more common to use a 24 hour clock. This property allows you to
8450  * construct a formatter that overrides the default for the locale.<p>
8451  * 
8452  * If this property is not specified, the default is to use the most widely used convention
8453  * for the locale.
8454  *  
8455  * <li><i>template</i> - use the given template string as a fixed format when formatting 
8456  * the date/time. Valid codes to use in a template string are as follows:
8457  * 
8458  * <ul>
8459  * <li><i>a</i> - am/pm marker
8460  * <li><i>d</i> - 1 or 2 digit date of month, not padded
8461  * <li><i>dd</i> - 1 or 2 digit date of month, 0 padded to 2 digits
8462  * <li><i>O</i> - ordinal representation of the date of month (eg. "1st", "2nd", etc.)
8463  * <li><i>D</i> - 1 to 3 digit day of year
8464  * <li><i>DD</i> - 1 to 3 digit day of year, 0 padded to 2 digits
8465  * <li><i>DDD</i> - 1 to 3 digit day of year, 0 padded to 3 digits
8466  * <li><i>M</i> - 1 or 2 digit month number, not padded
8467  * <li><i>MM</i> - 1 or 2 digit month number, 0 padded to 2 digits
8468  * <li><i>N</i> - 1 character month name abbreviation
8469  * <li><i>NN</i> - 2 character month name abbreviation
8470  * <li><i>MMM</i> - 3 character month month name abbreviation
8471  * <li><i>MMMM</i> - fully spelled out month name
8472  * <li><i>yy</i> - 2 digit year
8473  * <li><i>yyyy</i> - 4 digit year
8474  * <li><i>E</i> - day-of-week name, abbreviated to a single character
8475  * <li><i>EE</i> - day-of-week name, abbreviated to a max of 2 characters
8476  * <li><i>EEE</i> - day-of-week name, abbreviated to a max of 3 characters
8477  * <li><i>EEEE</i> - day-of-week name fully spelled out 
8478  * <li><i>G</i> - era designator
8479  * <li><i>w</i> - week number in year
8480  * <li><i>ww</i> - week number in year, 0 padded to 2 digits
8481  * <li><i>W</i> - week in month
8482  * <li><i>h</i> - hour (12 followed by 1 to 11)
8483  * <li><i>hh</i> - hour (12, followed by 1 to 11), 0 padded to 2 digits
8484  * <li><i>k</i> - hour (1 to 24)
8485  * <li><i>kk</i> - hour (1 to 24), 0 padded to 2 digits
8486  * <li><i>H</i> - hour (0 to 23)
8487  * <li><i>HH</i> - hour (0 to 23), 0 padded to 2 digits
8488  * <li><i>K</i> - hour (0 to 11)
8489  * <li><i>KK</i> - hour (0 to 11), 0 padded to 2 digits
8490  * <li><i>m</i> - minute in hour
8491  * <li><i>mm</i> - minute in hour, 0 padded to 2 digits
8492  * <li><i>s</i> - second in minute
8493  * <li><i>ss</i> - second in minute, 0 padded to 2 digits
8494  * <li><i>S</i> - millisecond (1 to 3 digits)
8495  * <li><i>SSS</i> - millisecond, 0 padded to 3 digits
8496  * <li><i>z</i> - general time zone
8497  * <li><i>Z</i> - RFC 822 time zone
8498  * </ul>
8499  * 
8500  * <li><i>useNative</i> - the flag used to determine whether to use the native script settings 
8501  * for formatting the numbers.
8502  *
8503  * <li><i>meridiems</i> - string that specifies what style of meridiems to use with this 
8504  * format. The choices are "default", "gregorian", "ethiopic", and "chinese". The "default" 
8505  * style is often the simple Gregorian AM/PM, but the actual style is chosen by the locale. 
8506  * (For almost all locales, the Gregorian AM/PM style is most frequently used.)
8507  * The "ethiopic" style uses 5 different meridiems for "morning", "noon", "afternoon", 
8508  * "evening", and "night". The "chinese" style uses 7 different meridiems corresponding 
8509  * to the various parts of the day. N.B. Even for the Chinese locales, the default is "gregorian"
8510  * when formatting dates in the Gregorian calendar.
8511  *
8512  * <li><i>onLoad</i> - a callback function to call when the date format object is fully 
8513  * loaded. When the onLoad option is given, the DateFmt object will attempt to
8514  * load any missing locale data using the ilib loader callback.
8515  * When the constructor is done (even if the data is already preassembled), the 
8516  * onLoad function is called with the current instance as a parameter, so this
8517  * callback can be used with preassembled or dynamic loading or a mix of the two.
8518  * 
8519  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
8520  * asynchronously. If this option is given as "false", then the "onLoad"
8521  * callback must be given, as the instance returned from this constructor will
8522  * not be usable for a while.
8523  *  
8524  * <li><i>loadParams</i> - an object containing parameters to pass to the 
8525  * loader callback function when locale data is missing. The parameters are not
8526  * interpretted or modified in any way. They are simply passed along. The object 
8527  * may contain any property/value pairs as long as the calling code is in
8528  * agreement with the loader callback function as to what those parameters mean.
8529  * </ul>
8530  * 
8531  * Any substring containing letters within single or double quotes will be used 
8532  * as-is in the final output and will not be interpretted for codes as above.<p>
8533  * 
8534  * Example: a date format in Spanish might be given as: "'El' d. 'de' MMMM", where
8535  * the 'El' and the 'de' are left as-is in the output because they are quoted. Typical 
8536  * output for this example template might be, "El 5. de Mayo".
8537  * 
8538  * The following options will be used when formatting a date/time with an explicit
8539  * template:
8540  * 
8541  * <ul>
8542  * <li>locale - the locale is only used for 
8543  * translations of things like month names or day-of-week names.
8544  * <li>calendar - used to translate a date instance into date/time component values 
8545  * that can be formatted into the template
8546  * <li>timezone - used to figure out the offset to add or subtract from the time to
8547  * get the final time component values
8548  * <li>clock - used to figure out whether to format times with a 12 or 24 hour clock.
8549  * If this option is specified, it will override the hours portion of a time format.
8550  * That is, "hh" is switched with "HH" and "kk" is switched with "KK" as appropriate. 
8551  * If this option is not specified, the 12/24 code in the template will dictate whether 
8552  * to use the 12 or 24 clock, and the 12/24 default in the locale will be ignored.
8553  * </ul>
8554  * 
8555  * All other options will be ignored and their corresponding getter methods will
8556  * return the empty string.<p>
8557  * 
8558  * 
8559  * @constructor
8560  * @param {Object} options options governing the way this date formatter instance works
8561  */
8562 var DateFmt = function(options) {
8563 	var arr, i, bad, 
8564 		sync = true, 
8565 		loadParams = undefined;
8566 	
8567 	this.locale = new Locale();
8568 	this.type = "date";
8569 	this.length = "s";
8570 	this.dateComponents = "dmy";
8571 	this.timeComponents = "ahm";
8572 	this.meridiems = "default";
8573 	
8574 	if (options) {
8575 		if (options.locale) {
8576 			this.locale = (typeof(options.locale) === 'string') ? new Locale(options.locale) : options.locale;
8577 		}
8578 		
8579 		if (options.type) {
8580 			if (options.type === 'date' || options.type === 'time' || options.type === 'datetime') {
8581 				this.type = options.type;
8582 			}
8583 		}
8584 		
8585 		if (options.calendar) {
8586 			this.calName = options.calendar;
8587 		}
8588 		
8589 		if (options.length) {
8590 			if (options.length === 'short' ||
8591 				options.length === 'medium' ||
8592 				options.length === 'long' ||
8593 				options.length === 'full') {
8594 				// only use the first char to save space in the json files
8595 				this.length = options.length.charAt(0);
8596 			}
8597 		}
8598 		
8599 		if (options.date) {
8600 			arr = options.date.split("");
8601 			var dateComps = new ISet();
8602 			bad = false;
8603 			for (i = 0; i < arr.length; i++) {
8604 				var c = arr[i].toLowerCase();
8605 				if (c === "e") c = "w"; // map ICU -> ilib
8606 				if (c !== 'd' && c !== 'm' && c !== 'y' && c !== 'w' && c !== 'n') {
8607 					// ignore time components and the era
8608 					if (c !== 'h' && c !== 'm'  && c !== 's' && c !== 'a' && c !== 'z' && c !== 'g') {
8609     					bad = true;
8610     					break;
8611 					}
8612 				} else {
8613     				dateComps.add(c);
8614 				}
8615 			}
8616 			if (!bad) {
8617 				var comps = dateComps.asArray().sort(function (left, right) {
8618 					return (left < right) ? -1 : ((right < left) ? 1 : 0);
8619 				});
8620 				this.dateComponents = comps.join("");
8621 			}
8622 		}
8623 
8624 		if (options.time) {
8625 			arr = options.time.split("");
8626 			var timeComps = new ISet();
8627 			this.badTime = false;
8628 			for (i = 0; i < arr.length; i++) {
8629 				var c = arr[i].toLowerCase();
8630 				if (c !== 'h' && c !== 'm' && c !== 's' && c !== 'a' && c !== 'z') {
8631 					// ignore the date components
8632 					if (c !== 'd' && c !== 'm' && c !== 'y' && c !== 'w' && c !== 'e' && c !== 'n' && c !== 'g') {
8633     					this.badTime = true;
8634     					break;
8635 					}
8636 				} else {
8637 					timeComps.add(c);
8638 				}
8639 			}
8640 			if (!this.badTime) {
8641 				var comps = timeComps.asArray().sort(function (left, right) {
8642 					return (left < right) ? -1 : ((right < left) ? 1 : 0);
8643 				});
8644 				this.timeComponents = comps.join("");
8645 			}
8646 		}
8647 		
8648 		if (options.clock && (options.clock === '12' || options.clock === '24')) {
8649 			this.clock = options.clock;
8650 		}
8651 		
8652 		if (options.template) {
8653 			// many options are not useful when specifying the template directly, so zero
8654 			// them out.
8655 			this.type = "";
8656 			this.length = "";
8657 			this.dateComponents = "";
8658 			this.timeComponents = "";
8659 			
8660 			this.template = options.template;
8661 		}
8662 		
8663 		if (options.timezone) {
8664 			if (options.timezone instanceof TimeZone) {
8665 				this.tz = options.timezone;
8666 			} else {
8667 				this.tz = new TimeZone({
8668 					locale: this.locale, 
8669 					id: options.timezone
8670 				});
8671 			}
8672 		} else if (options.locale) {
8673 			// if an explicit locale was given, then get the time zone for that locale
8674 			this.tz = new TimeZone({
8675 				locale: this.locale
8676 			});
8677 		} // else just assume time zone "local"
8678 		
8679 		if (typeof(options.useNative) === 'boolean') {
8680 			this.useNative = options.useNative;
8681 		}
8682 		
8683 		if (typeof(options.meridiems) !== 'undefined' && 
8684 				(options.meridiems === "chinese" || 
8685 				 options.meridiems === "gregorian" || 
8686 				 options.meridiems === "ethiopic")) {
8687 			this.meridiems = options.meridiems;
8688 		}
8689 		
8690 		if (typeof(options.sync) !== 'undefined') {
8691 			sync = (options.sync === true);
8692 		}
8693 		
8694 		loadParams = options.loadParams;
8695 	}
8696 
8697 	if (!DateFmt.cache) {
8698 		DateFmt.cache = {};
8699 	}
8700 
8701 	new LocaleInfo(this.locale, {
8702 		sync: sync,
8703 		loadParams: loadParams, 
8704 		onLoad: ilib.bind(this, function (li) {
8705 			this.locinfo = li;
8706 			
8707 			// get the default calendar name from the locale, and if the locale doesn't define
8708 			// one, use the hard-coded gregorian as the last resort
8709 			this.calName = this.calName || this.locinfo.getCalendar() || "gregorian";
8710 			if (ilib.isDynCode()) {
8711 				// If we are running in the dynamic code loading assembly of ilib, the following
8712 				// will attempt to dynamically load the calendar date class for this calendar. If 
8713 				// it doesn't work, this just goes on and it will use Gregorian instead.
8714 				DateFactory._dynLoadDate(this.calName);
8715 			}
8716 			
8717 			this.cal = CalendarFactory({
8718 				type: this.calName
8719 			});
8720 			if (!this.cal) {
8721 				this.cal = new GregorianCal();
8722 			}
8723 			if (this.meridiems === "default") {
8724 				this.meridiems = li.getMeridiemsStyle();
8725 			}
8726 
8727 			/*
8728 			if (this.timeComponents &&
8729 					(this.clock === '24' || 
8730 					(!this.clock && this.locinfo.getClock() === "24"))) {
8731 				// make sure we don't have am/pm in 24 hour mode unless the user specifically
8732 				// requested it in the time component option
8733 				this.timeComponents = this.timeComponents.replace("a", "");
8734 			}
8735 			*/
8736 
8737 			// load the strings used to translate the components
8738 			new ResBundle({
8739 				locale: this.locale,
8740 				name: "sysres",
8741 				sync: sync,
8742 				loadParams: loadParams, 
8743 				onLoad: ilib.bind(this, function (rb) {
8744 					this.sysres = rb;
8745 					
8746 					if (!this.template) {
8747 						Utils.loadData({
8748 							object: DateFmt, 
8749 							locale: this.locale, 
8750 							name: "dateformats.json", 
8751 							sync: sync, 
8752 							loadParams: loadParams, 
8753 							callback: ilib.bind(this, function (formats) {
8754 								if (!formats) {
8755 									formats = ilib.data.dateformats || DateFmt.defaultFmt;
8756 									var spec = this.locale.getSpec().replace(/-/g, '_');
8757 									DateFmt.cache[spec] = formats;
8758 								}
8759 								if (typeof(this.clock) === 'undefined') {
8760 									// default to the locale instead
8761 									this.clock = this.locinfo.getClock();
8762 								}
8763 								this._initTemplate(formats);
8764 								this._massageTemplate();
8765 								if (options && typeof(options.onLoad) === 'function') {
8766 									options.onLoad(this);
8767 								}
8768 							})
8769 						});
8770 					} else {
8771 						this._massageTemplate();
8772 						if (options && typeof(options.onLoad) === 'function') {
8773 							options.onLoad(this);
8774 						}
8775 					}
8776 				})
8777 			});	
8778 		})
8779 	});
8780 };
8781 
8782 // used in getLength
8783 DateFmt.lenmap = {
8784 	"s": "short",
8785 	"m": "medium",
8786 	"l": "long",
8787 	"f": "full"
8788 };
8789 
8790 DateFmt.defaultFmt = {
8791 	"gregorian": {
8792 		"order": "{date} {time}",
8793 		"date": {
8794 			"dmwy": "EEE d/MM/yyyy",
8795 			"dmy": "d/MM/yyyy",
8796 			"dmw": "EEE d/MM",
8797 			"dm": "d/MM",
8798 			"my": "MM/yyyy",
8799 			"dw": "EEE d",
8800 			"d": "dd",
8801 			"m": "MM",
8802 			"y": "yyyy",
8803 			"n": "NN",
8804 			"w": "EEE"
8805 		},
8806 		"time": {
8807 			"12": "h:mm:ssa",
8808 			"24": "H:mm:ss"
8809 		},
8810 		"range": {
8811 			"c00": "{st} - {et}, {sd}/{sm}/{sy}",
8812 			"c01": "{sd}/{sm} {st} - {ed}/{em} {et}, {sy}",
8813 			"c02": "{sd}/{sm} {st} - {ed}/{em} {et}, {sy}",
8814 			"c03": "{sd}/{sm}/{sy} {st} - {ed}/{em}/{ey} {et}",
8815 			"c10": "{sd}-{ed}/{sm}/{sy}",
8816 			"c11": "{sd}/{sm} - {ed}/{em} {sy}",
8817 			"c12": "{sd}/{sm}/{sy} - {ed}/{em}/{ey}",
8818 			"c20": "{sm}/{sy} - {em}/{ey}",
8819 			"c30": "{sy} - {ey}"
8820 		}
8821 	},
8822 	"islamic": "gregorian",
8823 	"hebrew": "gregorian",
8824 	"julian": "gregorian",
8825 	"buddhist": "gregorian",
8826 	"persian": "gregorian",
8827 	"persian-algo": "gregorian",
8828 	"han": "gregorian"
8829 };
8830 
8831 /**
8832 * @static
8833 * @private
8834 */
8835 DateFmt.monthNameLenMap = {
8836 	"short" : "N",
8837 	"medium": "NN",
8838 	"long":   "MMM",
8839 	"full":   "MMMM"
8840 };
8841 
8842 /**
8843 * @static
8844 * @private
8845 */
8846 DateFmt.weekDayLenMap = {
8847 	"short" : "E",
8848 	"medium": "EE",
8849 	"long":   "EEE",
8850 	"full":   "EEEE"
8851 };
8852 
8853 /**
8854  * Return the range of possible meridiems (times of day like "AM" or 
8855  * "PM") in this date formatter.<p>
8856  *
8857  * The options may contain any of the following properties:
8858  *
8859  * <ul>
8860  * <li><i>locale</i> - locale to use when formatting the date/time. If the locale is
8861  * not specified, then the default locale of the app or web page will be used.
8862  * 
8863  * <li><i>meridiems</i> - string that specifies what style of meridiems to use with this 
8864  * format. The choices are "default", "gregorian", "ethiopic", and "chinese". The "default" 
8865  * style is often the simple Gregorian AM/PM, but the actual style is chosen by the locale. 
8866  * (For almost all locales, the Gregorian AM/PM style is most frequently used.)
8867  * The "ethiopic" style uses 5 different meridiems for "morning", "noon", "afternoon", 
8868  * "evening", and "night". The "chinese" style uses 7 different meridiems corresponding 
8869  * to the various parts of the day. N.B. Even for the Chinese locales, the default is "gregorian"
8870  * when formatting dates in the Gregorian calendar.
8871  * </ul>
8872  *
8873  * @static
8874  * @public
8875  * @param {Object} options options governing the way this date formatter instance works for getting meridiems range
8876  * @return {Array.<{name:string,start:string,end:string}>}
8877  */
8878 DateFmt.getMeridiemsRange = function (options) {
8879 	options = options || {};
8880 	var args = {};
8881 	if (options.locale) {
8882 		args.locale = options.locale;
8883 	}
8884 
8885 	if (options.meridiems) {
8886 		args.meridiems = options.meridiems;
8887 	}
8888 
8889 	var fmt = new DateFmt(args);
8890 
8891 	return fmt.getMeridiemsRange();
8892 };
8893 
8894 DateFmt.prototype = {
8895 	/**
8896 	 * @protected
8897 	 * @param {string|{
8898 	 * 		order:(string|{
8899 	 * 			s:string,
8900 	 * 			m:string,
8901 	 * 			l:string,
8902 	 * 			f:string
8903 	 * 		}),
8904 	 * 		date:Object.<string, (string|{
8905 	 * 			s:string,
8906 	 * 			m:string,
8907 	 * 			l:string,
8908 	 * 			f:string
8909 	 * 		})>,
8910 	 * 		time:Object.<string,Object.<string,(string|{
8911 	 * 			s:string,
8912 	 * 			m:string,
8913 	 * 			l:string,
8914 	 * 			f:string
8915 	 * 		})>>,
8916 	 * 		range:Object.<string, (string|{
8917 	 * 			s:string,
8918 	 * 			m:string,
8919 	 * 			l:string,
8920 	 * 			f:string
8921 	 * 		})>
8922 	 * 	}} formats
8923 	 */
8924 	_initTemplate: function (formats) {
8925 		if (formats[this.calName]) {
8926 			var name = formats[this.calName];
8927 			// may be an alias to another calendar type
8928 			this.formats = (typeof(name) === "string") ? formats[name] : name;
8929 			
8930 			this.template = "";
8931 			
8932 			switch (this.type) {
8933 				case "datetime":
8934 					this.template = (this.formats && this._getLengthFormat(this.formats.order, this.length)) || "{date} {time}";
8935 					this.template = this.template.replace("{date}", this._getFormat(this.formats.date, this.dateComponents, this.length) || "");
8936 					this.template = this.template.replace("{time}", this._getFormat(this.formats.time[this.clock], this.timeComponents, this.length) || "");
8937 					break;
8938 				case "date":
8939 					this.template = this._getFormat(this.formats.date, this.dateComponents, this.length);
8940 					break;
8941 				case "time":
8942 					this.template = this._getFormat(this.formats.time[this.clock], this.timeComponents, this.length);
8943 					break;
8944 			}
8945 		} else {
8946 			throw "No formats available for calendar " + this.calName + " in locale " + this.locale.toString();
8947 		}
8948 	},
8949 	
8950 	/**
8951 	 * @protected
8952 	 */
8953 	_massageTemplate: function () {
8954 		var i;
8955 		
8956 		if (this.clock && this.template) {
8957 			// explicitly set the hours to the requested type
8958 			var temp = "";
8959 			switch (this.clock) {
8960 				case "24":
8961 					for (i = 0; i < this.template.length; i++) {
8962 						if (this.template.charAt(i) == "'") {
8963 							temp += this.template.charAt(i++);
8964 							while (i < this.template.length && this.template.charAt(i) !== "'") {
8965 								temp += this.template.charAt(i++);
8966 							}
8967 							if (i < this.template.length) {
8968 								temp += this.template.charAt(i);
8969 							}
8970 						} else if (this.template.charAt(i) == 'K') {
8971 							temp += 'k';
8972 						} else if (this.template.charAt(i) == 'h') {
8973 							temp += 'H';
8974 						} else {
8975 							temp += this.template.charAt(i);
8976 						}
8977 					}
8978 					this.template = temp;
8979 					break;
8980 				case "12":
8981 					for (i = 0; i < this.template.length; i++) {
8982 						if (this.template.charAt(i) == "'") {
8983 							temp += this.template.charAt(i++);
8984 							while (i < this.template.length && this.template.charAt(i) !== "'") {
8985 								temp += this.template.charAt(i++);
8986 							}
8987 							if (i < this.template.length) {
8988 								temp += this.template.charAt(i);
8989 							}
8990 						} else if (this.template.charAt(i) == 'k') {
8991 							temp += 'K';
8992 						} else if (this.template.charAt(i) == 'H') {
8993 							temp += 'h';
8994 						} else {
8995 							temp += this.template.charAt(i);
8996 						}
8997 					}
8998 					this.template = temp;
8999 					break;
9000 			}
9001 		}
9002 		
9003 		// tokenize it now for easy formatting
9004 		this.templateArr = this._tokenize(this.template);
9005 
9006 		var digits;
9007 		// set up the mapping to native or alternate digits if necessary
9008 		if (typeof(this.useNative) === "boolean") {
9009 			if (this.useNative) {
9010 				digits = this.locinfo.getNativeDigits();
9011 				if (digits) {
9012 					this.digits = digits;
9013 				}
9014 			}
9015 		} else if (this.locinfo.getDigitsStyle() === "native") {
9016 			digits = this.locinfo.getNativeDigits();
9017 			if (digits) {
9018 				this.useNative = true;
9019 				this.digits = digits;
9020 			}
9021 		}
9022 	},
9023     
9024 	/**
9025 	 * Convert the template into an array of date components separated by formatting chars.
9026 	 * @protected
9027 	 * @param {string} template Format template to tokenize into components
9028 	 * @return {Array.<string>} a tokenized array of date format components
9029 	 */
9030 	_tokenize: function (template) {
9031 		var i = 0, start, ch, letter, arr = [];
9032 		
9033 		// console.log("_tokenize: tokenizing template " + template);
9034 		if (template) {
9035 			while (i < template.length) {
9036 				ch = template.charAt(i);
9037 				start = i;
9038 				if (ch === "'") {
9039 					// console.log("found quoted string");
9040 					i++;
9041 					// escaped string - push as-is, then dequote later
9042 					while (i < template.length && template.charAt(i) !== "'") {
9043 						i++;
9044 					}
9045 					if (i < template.length) {
9046 						i++;	// grab the other quote too
9047 					}
9048 				} else if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) {
9049 					letter = template.charAt(i);
9050 					// console.log("found letters " + letter);
9051 					while (i < template.length && ch === letter) {
9052 						ch = template.charAt(++i);
9053 					}
9054 				} else {
9055 					// console.log("found other");
9056 					while (i < template.length && ch !== "'" && (ch < 'a' || ch > 'z') && (ch < 'A' || ch > 'Z')) {
9057 						ch = template.charAt(++i);
9058 					}
9059 				}
9060 				arr.push(template.substring(start,i));
9061 				// console.log("start is " + start + " i is " + i + " and substr is " + template.substring(start,i));
9062 			}
9063 		}
9064 		return arr;
9065 	},
9066     
9067 	/**
9068 	 * @protected
9069 	 * @param {Object.<string, (string|{s:string,m:string,l:string,f:string})>} obj Object to search
9070 	 * @param {string} components Format components to search
9071 	 * @param {string} length Length of the requested format
9072 	 * @return {string|undefined} the requested format
9073 	 */
9074 	_getFormatInternal: function getFormatInternal(obj, components, length) {
9075 		if (typeof(components) !== 'undefined' && obj && obj[components]) {
9076 			return this._getLengthFormat(obj[components], length);
9077 		}
9078 		return undefined;
9079 	},
9080 
9081 	// stand-alone of m (month) is t
9082 	// stand-alone of d (day) is a
9083 	// stand-alone of w (weekday) is l
9084 	// stand-alone of y (year) is r
9085 	_standAlones: {
9086 		"m": "t",
9087 		"d": "a",
9088 		"w": "l",
9089 		"y": "r"
9090 	},
9091 	
9092 	/**
9093 	 * @protected
9094 	 * @param {Object.<string, (string|{s:string,m:string,l:string,f:string})>} obj Object to search
9095 	 * @param {string} components Format components to search
9096 	 * @param {string} length Length of the requested format
9097 	 * @return {string|undefined} the requested format
9098 	 */
9099 	_getFormat: function getFormat(obj, components, length) {
9100 		// handle some special cases for stand-alone formats
9101 		if (components && this._standAlones[components]) {
9102     		var tmp = this._getFormatInternal(obj, this._standAlones[components], length);
9103     		if (tmp) {
9104     			return tmp;
9105     		}
9106 		}
9107 		
9108 		// if no stand-alone format is available, fall back to the regular format
9109 		return this._getFormatInternal(obj, components, length);
9110 	},
9111 
9112 	/**
9113 	 * @protected
9114 	 * @param {(string|{s:string,m:string,l:string,f:string})} obj Object to search
9115 	 * @param {string} length Length of the requested format
9116 	 * @return {(string|undefined)} the requested format
9117 	 */
9118 	_getLengthFormat: function getLengthFormat(obj, length) {
9119 		if (typeof(obj) === 'string') {
9120 			return obj;
9121 		} else if (obj[length]) {
9122 			return obj[length];
9123 		}
9124 		return undefined;
9125 	},
9126 
9127 	/**
9128 	 * Return the locale used with this formatter instance.
9129 	 * @return {Locale} the Locale instance for this formatter
9130 	 */
9131 	getLocale: function() {
9132 		return this.locale;
9133 	},
9134 	
9135 	/**
9136 	 * Return the template string that is used to format date/times for this
9137 	 * formatter instance. This will work, even when the template property is not explicitly 
9138 	 * given in the options to the constructor. Without the template option, the constructor 
9139 	 * will build the appropriate template according to the options and use that template
9140 	 * in the format method. 
9141 	 * 
9142 	 * @return {string} the format template for this formatter
9143 	 */
9144 	getTemplate: function() {
9145 		return this.template;
9146 	},
9147 	
9148 	/**
9149 	 * Return the type of this formatter. The type is a string that has one of the following
9150 	 * values: "time", "date", "datetime".
9151 	 * @return {string} the type of the formatter
9152 	 */
9153 	getType: function() {
9154 		return this.type;
9155 	},
9156 	
9157 	/**
9158 	 * Return the name of the calendar used to format date/times for this
9159 	 * formatter instance.
9160 	 * @return {string} the name of the calendar used by this formatter
9161 	 */
9162 	getCalendar: function () {
9163 		return this.cal.getType();
9164 	},
9165 	
9166 	/**
9167 	 * Return the length used to format date/times in this formatter. This is either the
9168 	 * value of the length option to the constructor, or the default value.
9169 	 * 
9170 	 * @return {string} the length of formats this formatter returns
9171 	 */
9172 	getLength: function () {
9173 		return DateFmt.lenmap[this.length] || "";
9174 	},
9175 	
9176 	/**
9177 	 * Return the date components that this formatter formats. This is either the 
9178 	 * value of the date option to the constructor, or the default value. If this
9179 	 * formatter is a time-only formatter, this method will return the empty 
9180 	 * string. The date component letters may be specified in any order in the 
9181 	 * constructor, but this method will reorder the given components to a standard 
9182 	 * order.
9183 	 * 
9184 	 * @return {string} the date components that this formatter formats
9185 	 */
9186 	getDateComponents: function () {
9187 		return this.dateComponents || "";
9188 	},
9189 
9190 	/**
9191 	 * Return the time components that this formatter formats. This is either the 
9192 	 * value of the time option to the constructor, or the default value. If this
9193 	 * formatter is a date-only formatter, this method will return the empty 
9194 	 * string. The time component letters may be specified in any order in the 
9195 	 * constructor, but this method will reorder the given components to a standard 
9196 	 * order.
9197 	 * 
9198 	 * @return {string} the time components that this formatter formats
9199 	 */
9200 	getTimeComponents: function () {
9201 		return this.timeComponents || "";
9202 	},
9203 
9204 	/**
9205 	 * Return the time zone used to format date/times for this formatter
9206 	 * instance.
9207 	 * @return a string naming the time zone
9208 	 */
9209 	getTimeZone: function () {
9210 		// Lazy load the time zone. If it wasn't explicitly set up before, set 
9211 		// it up now, but use the 
9212 		// default TZ for the locale. This way, if the caller never uses the
9213 		// time zone in their format, we never have to load up a TimeZone
9214 		// instance into this formatter.
9215 		if (!this.tz) {
9216 			this.tz = new TimeZone({id: ilib.getTimeZone()});
9217 		}
9218 		return this.tz;
9219 	},
9220 	/**
9221 	 * Return the clock option set in the constructor. If the clock option was
9222 	 * not given, the default from the locale is returned instead.
9223 	 * @return {string} "12" or "24" depending on whether this formatter uses
9224 	 * the 12-hour or 24-hour clock
9225 	 */
9226 	getClock: function () {
9227 		return this.clock || this.locinfo.getClock();
9228 	},
9229 	/**
9230 	 * Return the meridiems range in current locale. 
9231 	 * @return {Array.<{name:string,start:string,end:string}>} the range of available meridiems
9232 	 */
9233 	getMeridiemsRange: function () {
9234 		var result;
9235 		var _getSysString = function (key) {
9236 			return (this.sysres.getString(undefined, key + "-" + this.calName) || this.sysres.getString(undefined, key)).toString();
9237 		};
9238 
9239 		switch (this.meridiems) {
9240 		case "chinese":
9241 			result = [
9242 				{
9243 					name: _getSysString.call(this, "azh0"),
9244 					start: "00:00",
9245 					end: "05:59"
9246 				},
9247 				{
9248 					name: _getSysString.call(this, "azh1"),
9249 					start: "06:00",
9250 					end: "08:59"
9251 				},
9252 				{
9253 					name: _getSysString.call(this, "azh2"),
9254 					start: "09:00",
9255 					end: "11:59"
9256 				},
9257 				{
9258 					name: _getSysString.call(this, "azh3"),
9259 					start: "12:00",
9260 					end: "12:59"
9261 				},
9262 				{
9263 					name: _getSysString.call(this, "azh4"),
9264 					start: "13:00",
9265 					end: "17:59"
9266 				},
9267 				{
9268 					name: _getSysString.call(this, "azh5"),
9269 					start: "18:00",
9270 					end: "20:59"
9271 				},
9272 				{
9273 					name: _getSysString.call(this, "azh6"),
9274 					start: "21:00",
9275 					end: "23:59"
9276 				}
9277 			];
9278 			break;
9279 		case "ethiopic":
9280 			result = [
9281 				{
9282 					name: _getSysString.call(this, "a0-ethiopic"),
9283 					start: "00:00",
9284 					end: "05:59"
9285 				},
9286 				{
9287 					name: _getSysString.call(this, "a1-ethiopic"),
9288 					start: "06:00",
9289 					end: "06:00"
9290 				},
9291 				{
9292 					name: _getSysString.call(this, "a2-ethiopic"),
9293 					start: "06:01",
9294 					end: "11:59"
9295 				},
9296 				{
9297 					name: _getSysString.call(this, "a3-ethiopic"),
9298 					start: "12:00",
9299 					end: "17:59"
9300 				},
9301 				{
9302 					name: _getSysString.call(this, "a4-ethiopic"),
9303 					start: "18:00",
9304 					end: "23:59"
9305 				}
9306 			];
9307 			break;
9308 		default:
9309 			result = [
9310 				{
9311 					name: _getSysString.call(this, "a0"),
9312 					start: "00:00",
9313 					end: "11:59"
9314 				},
9315 				{
9316 					name: _getSysString.call(this, "a1"),
9317 					start: "12:00",
9318 					end: "23:59"
9319 				}
9320 			];
9321 			break;
9322 		}
9323 
9324 		return result;
9325 	},
9326 	
9327 	/**
9328 	 * @private
9329 	 */
9330 	_getTemplate: function (prefix, calendar) {
9331 		if (calendar !== "gregorian") {
9332 			return prefix + "-" + calendar;
9333 		}
9334 		return prefix;
9335 	},
9336 
9337 	/**
9338 	 * Returns an array of the months of the year, formatted to the optional length specified.
9339 	 * i.e. ...getMonthsOfYear() OR ...getMonthsOfYear({length: "short"})
9340 	 * <p>
9341 	 * The options parameter may contain any of the following properties:
9342 	 * 
9343 	 * <ul>
9344 	 * <li><i>length</i> - length of the names of the months being sought. This may be one of
9345 	 * "short", "medium", "long", or "full"
9346 	 * <li><i>date</i> - retrieve the names of the months in the date of the given date
9347 	 * <li><i>year</i> - retrieve the names of the months in the given year. In some calendars,
9348 	 * the months have different names depending if that year is a leap year or not.
9349 	 * </ul>
9350 	 * 
9351 	 * @param  {Object=} options an object-literal that contains any of the above properties
9352 	 * @return {Array} an array of the names of all of the months of the year in the current calendar
9353 	 */
9354 	getMonthsOfYear: function(options) {
9355 		var length = (options && options.length) || this.getLength(),
9356 			template = DateFmt.monthNameLenMap[length],
9357 			months = [undefined],
9358 			date,
9359 			monthCount;
9360 		
9361 		if (options) {
9362 			if (options.date) {
9363 				date = DateFactory._dateToIlib(options.date); 	
9364 			}
9365 			
9366 			if (options.year) {
9367 				date = DateFactory({year: options.year, month: 1, day: 1, type: this.cal.getType()});
9368 			}
9369 		}
9370 		
9371 		if (!date) {
9372 			date = DateFactory({
9373 				calendar: this.cal.getType()
9374 			});
9375 		}
9376 
9377 		monthCount = this.cal.getNumMonths(date.getYears());
9378 		for (var i = 1; i <= monthCount; i++) {
9379 			months[i] = this.sysres.getString(this._getTemplate(template + i, this.cal.getType())).toString();
9380 		}
9381 		return months;
9382 	},
9383 
9384 	/**
9385 	 * Returns an array of the days of the week, formatted to the optional length specified.
9386 	 * i.e. ...getDaysOfWeek() OR ...getDaysOfWeek({length: "short"})
9387 	 * <p>
9388 	 * The options parameter may contain any of the following properties:
9389 	 * 
9390 	 * <ul>
9391 	 * <li><i>length</i> - length of the names of the months being sought. This may be one of
9392 	 * "short", "medium", "long", or "full"
9393 	 * </ul>
9394 	 * @param  {Object=} options an object-literal that contains one key 
9395 	 *                   "length" with the standard length strings
9396 	 * @return {Array} an array of all of the names of the days of the week
9397 	 */
9398 	getDaysOfWeek: function(options) {
9399 		var length = (options && options.length) || this.getLength(),
9400 			template = DateFmt.weekDayLenMap[length],
9401 			days = [];
9402 		for (var i = 0; i < 7; i++) {
9403 			days[i] = this.sysres.getString(this._getTemplate(template + i, this.cal.getType())).toString();
9404 		}
9405 		return days;
9406 	},
9407 
9408 	
9409 	/**
9410 	 * Convert this formatter to a string representation by returning the
9411 	 * format template. This method delegates to getTemplate.
9412 	 * 
9413 	 * @return {string} the format template
9414 	 */
9415 	toString: function() {
9416 		return this.getTemplate();
9417 	},
9418 		
9419 	/**
9420 	 * @private
9421 	 * Format a date according to a sequence of components. 
9422 	 * @param {IDate} date a date/time object to format
9423 	 * @param {Array.<string>} templateArr an array of components to format
9424 	 * @return {string} the formatted date
9425 	 */
9426 	_formatTemplate: function (date, templateArr) {
9427 		var i, key, temp, tz, str = "";
9428 		for (i = 0; i < templateArr.length; i++) {
9429 			switch (templateArr[i]) {
9430 				case 'd':
9431 					str += (date.day || 1);
9432 					break;
9433 				case 'dd':
9434 					str += JSUtils.pad(date.day || "1", 2);
9435 					break;
9436 				case 'yy':
9437 					temp = "" + ((date.year || 0) % 100);
9438 					str += JSUtils.pad(temp, 2);
9439 					break;
9440 				case 'yyyy':
9441 					str += JSUtils.pad(date.year || "0", 4);
9442 					break;
9443 				case 'M':
9444 					str += (date.month || 1);
9445 					break;
9446 				case 'MM':
9447 					str += JSUtils.pad(date.month || "1", 2);
9448 					break;
9449 				case 'h':
9450 					temp = (date.hour || 0) % 12;
9451 					if (temp == 0) {
9452 						temp = "12";
9453 					}
9454 					str += temp; 
9455 					break;
9456 				case 'hh':
9457 					temp = (date.hour || 0) % 12;
9458 					if (temp == 0) {
9459 						temp = "12";
9460 					}
9461 					str += JSUtils.pad(temp, 2);
9462 					break;
9463 				/*
9464 				case 'j':
9465 					temp = (date.hour || 0) % 12 + 1;
9466 					str += temp; 
9467 					break;
9468 				case 'jj':
9469 					temp = (date.hour || 0) % 12 + 1;
9470 					str += JSUtils.pad(temp, 2);
9471 					break;
9472 				*/
9473 				case 'K':
9474 					temp = (date.hour || 0) % 12;
9475 					str += temp; 
9476 					break;
9477 				case 'KK':
9478 					temp = (date.hour || 0) % 12;
9479 					str += JSUtils.pad(temp, 2);
9480 					break;
9481 
9482 				case 'H':
9483 					str += (date.hour || "0");
9484 					break;
9485 				case 'HH':
9486 					str += JSUtils.pad(date.hour || "0", 2);
9487 					break;
9488 				case 'k':
9489 					str += (date.hour == 0 ? "24" : date.hour);
9490 					break;
9491 				case 'kk':
9492 					temp = (date.hour == 0 ? "24" : date.hour);
9493 					str += JSUtils.pad(temp, 2);
9494 					break;
9495 
9496 				case 'm':
9497 					str += (date.minute || "0");
9498 					break;
9499 				case 'mm':
9500 					str += JSUtils.pad(date.minute || "0", 2);
9501 					break;
9502 				case 's':
9503 					str += (date.minute || "0");
9504 					break;
9505 				case 'ss':
9506 					str += JSUtils.pad(date.second || "0", 2);
9507 					break;
9508 				case 'S':
9509 					str += (date.millisecond || "0");
9510 					break;
9511 				case 'SSS':
9512 					str += JSUtils.pad(date.millisecond || "0", 3);
9513 					break;
9514 
9515 				case 'N':
9516 				case 'NN':
9517 				case 'MMM':
9518 				case 'MMMM':
9519 				case 'L':
9520 				case 'LL':
9521 				case 'LLL':
9522 				case 'LLLL':
9523 					key = templateArr[i] + (date.month || 1);
9524 					str += (this.sysres.getString(undefined, key + "-" + this.calName) || this.sysres.getString(undefined, key));
9525 					break;
9526 					
9527 				case 'E':
9528 				case 'EE':
9529 				case 'EEE':
9530 				case 'EEEE':
9531 				case 'c':
9532 				case 'cc':
9533 				case 'ccc':
9534 				case 'cccc':
9535 					key = templateArr[i] + date.getDayOfWeek();
9536 					//console.log("finding " + key + " in the resources");
9537 					str += (this.sysres.getString(undefined, key + "-" + this.calName) || this.sysres.getString(undefined, key));
9538 					break;
9539 
9540 				case 'a':
9541 					switch (this.meridiems) {
9542 					case "chinese":
9543 						if (date.hour < 6) {
9544 							key = "azh0";	// before dawn
9545 						} else if (date.hour < 9) {
9546 							key = "azh1";	// morning
9547 						} else if (date.hour < 12) {
9548 							key = "azh2";	// late morning/day before noon
9549 						} else if (date.hour < 13) {
9550 							key = "azh3";	// noon hour/midday
9551 						} else if (date.hour < 18) {
9552 							key = "azh4";	// afternoon
9553 						} else if (date.hour < 21) {
9554 							key = "azh5";	// evening time/dusk
9555 						} else {
9556 							key = "azh6";	// night time
9557 						}
9558 						break;
9559 					case "ethiopic":
9560 						if (date.hour < 6) {
9561 							key = "a0-ethiopic";	// morning
9562 						} else if (date.hour === 6 && date.minute === 0) {
9563 							key = "a1-ethiopic";	// noon
9564 						} else if (date.hour >= 6 && date.hour < 12) {
9565 							key = "a2-ethiopic";	// afternoon
9566 						} else if (date.hour >= 12 && date.hour < 18) {
9567 							key = "a3-ethiopic";	// evening
9568 						} else if (date.hour >= 18) {
9569 							key = "a4-ethiopic";	// night
9570 						}
9571 						break;
9572 					default:
9573 						key = date.hour < 12 ? "a0" : "a1";
9574 						break;
9575 					}
9576 					//console.log("finding " + key + " in the resources");
9577 					str += (this.sysres.getString(undefined, key + "-" + this.calName) || this.sysres.getString(undefined, key));
9578 					break;
9579 					
9580 				case 'w':
9581 					str += date.getWeekOfYear();
9582 					break;
9583 				case 'ww':
9584 					str += JSUtils.pad(date.getWeekOfYear(), 2);
9585 					break;
9586 
9587 				case 'D':
9588 					str += date.getDayOfYear();
9589 					break;
9590 				case 'DD':
9591 					str += JSUtils.pad(date.getDayOfYear(), 2);
9592 					break;
9593 				case 'DDD':
9594 					str += JSUtils.pad(date.getDayOfYear(), 3);
9595 					break;
9596 				case 'W':
9597 					str += date.getWeekOfMonth(this.locale);
9598 					break;
9599 
9600 				case 'G':
9601 					key = "G" + date.getEra();
9602 					str += (this.sysres.getString(undefined, key + "-" + this.calName) || this.sysres.getString(undefined, key));
9603 					break;
9604 
9605 				case 'O':
9606 					temp = this.sysres.getString("1#1st|2#2nd|3#3rd|21#21st|22#22nd|23#23rd|31#31st|#{num}th", "ordinalChoice");
9607 					str += temp.formatChoice(date.day, {num: date.day});
9608 					break;
9609 					
9610 				case 'z': // general time zone
9611 					tz = this.getTimeZone(); // lazy-load the tz
9612 					str += tz.getDisplayName(date, "standard");
9613 					break;
9614 				case 'Z': // RFC 822 time zone
9615 					tz = this.getTimeZone(); // lazy-load the tz
9616 					str += tz.getDisplayName(date, "rfc822");
9617 					break;
9618 
9619 				default:
9620 					str += templateArr[i].replace(/'/g, "");
9621 					break;
9622 			}
9623 		}
9624 
9625 		if (this.digits) {
9626 			str = JSUtils.mapString(str, this.digits);
9627 		}
9628 		return str;
9629 	},
9630 	
9631 	/**
9632 	 * Format a particular date instance according to the settings of this
9633 	 * formatter object. The type of the date instance being formatted must 
9634 	 * correspond exactly to the calendar type with which this formatter was 
9635 	 * constructed. If the types are not compatible, this formatter will
9636 	 * produce bogus results.
9637 	 * 
9638 	 * @param {IDate|Number|String|Date|JulianDay|null|undefined} dateLike a date-like object to format
9639 	 * @return {string} the formatted version of the given date instance
9640 	 */
9641 	format: function (dateLike) {
9642 		var thisZoneName = this.tz && this.tz.getId() || "local";
9643 
9644 		var date = DateFactory._dateToIlib(dateLike, thisZoneName, this.locale);
9645 		
9646 		if (!date.getCalendar || !(date instanceof IDate)) {
9647 			throw "Wrong date type passed to DateFmt.format()";
9648 		}
9649 		
9650 		var dateZoneName = date.timezone || "local";
9651 		
9652 		// convert to the time zone of this formatter before formatting
9653 		if (dateZoneName !== thisZoneName || date.getCalendar() !== this.calName) {
9654 			// console.log("Differing time zones date: " + dateZoneName + " and fmt: " + thisZoneName + ". Converting...");
9655 			// this will recalculate the date components based on the new time zone
9656 			// and/or convert a date in another calendar to the current calendar before formatting it
9657 			var newDate = DateFactory({
9658 				type: this.calName,
9659 				timezone: thisZoneName,
9660 				julianday: date.getJulianDay()
9661 			});
9662 			
9663 			date = newDate;
9664 		}
9665 		return this._formatTemplate(date, this.templateArr);
9666 	},
9667 	
9668 	/**
9669 	 * Return a string that describes a date relative to the given 
9670 	 * reference date. The string returned is text that for the locale that
9671 	 * was specified when the formatter instance was constructed.<p>
9672 	 * 
9673 	 * The date can be in the future relative to the reference date or in
9674 	 * the past, and the formatter will generate the appropriate string.<p>
9675 	 * 
9676 	 * The text used to describe the relative reference depends on the length
9677 	 * of time between the date and the reference. If the time was in the
9678 	 * past, it will use the "ago" phrase, and in the future, it will use
9679 	 * the "in" phrase. Examples:<p>
9680 	 * 
9681 	 * <ul>
9682 	 * <li>within a minute: either "X seconds ago" or "in X seconds"
9683 	 * <li>within an hour: either "X minutes ago" or "in X minutes"
9684 	 * <li>within a day: either "X hours ago" or "in X hours"
9685 	 * <li>within 2 weeks: either "X days ago" or "in X days"
9686 	 * <li>within 12 weeks (~3 months): either "X weeks ago" or "in X weeks"
9687 	 * <li>within two years: either "X months ago" or "in X months"
9688 	 * <li>longer than 2 years: "X years ago" or "in X years"
9689 	 * </ul>
9690 	 * 
9691 	 * @param {IDate|Number|String|Date|JulianDay|null|undefined} reference a date that the date parameter should be relative to
9692 	 * @param {IDate|Number|String|Date|JulianDay|null|undefined} date a date being formatted
9693 	 * @throws "Wrong calendar type" when the start or end dates are not the same
9694 	 * calendar type as the formatter itself
9695 	 * @return {string} the formatted relative date
9696 	 */
9697 	formatRelative: function(reference, date) {
9698 		reference = DateFactory._dateToIlib(reference);
9699 		date = DateFactory._dateToIlib(date);
9700 		
9701 		var referenceRd, dateRd, fmt, time, diff, num;
9702 		
9703 		if (typeof(reference) !== 'object' || !reference.getCalendar || reference.getCalendar() !== this.calName ||
9704 			typeof(date) !== 'object' || !date.getCalendar || date.getCalendar() !== this.calName) {
9705 			throw "Wrong calendar type";
9706 		}
9707 		
9708 		referenceRd = reference.getRataDie();
9709 		dateRd = date.getRataDie();
9710 		
9711 		if (dateRd < referenceRd) {
9712 			diff = referenceRd - dateRd;
9713 			fmt = this.sysres.getString("{duration} ago");
9714 		} else {
9715 			diff = dateRd - referenceRd;
9716 			fmt = this.sysres.getString("in {duration}");
9717 		}
9718 		
9719 		if (diff < 0.000694444) {
9720 			num = Math.round(diff * 86400);
9721 			switch (this.length) {
9722 				case 's':
9723 					time = this.sysres.getString("#{num}s");
9724 					break;
9725 				case 'm':
9726 					time = this.sysres.getString("1#1 se|#{num} sec");
9727 					break;
9728 				case 'l':
9729 					time = this.sysres.getString("1#1 sec|#{num} sec");
9730 					break;
9731 				default:
9732 				case 'f':
9733 					time = this.sysres.getString("1#1 second|#{num} seconds");
9734 					break;
9735 			}
9736 		} else if (diff < 0.041666667) {
9737 			num = Math.round(diff * 1440);
9738 			switch (this.length) {
9739 				case 's':
9740 					time = this.sysres.getString("#{num}m", "durationShortMinutes");
9741 					break;
9742 				case 'm':
9743 					time = this.sysres.getString("1#1 mi|#{num} min");
9744 					break;
9745 				case 'l':
9746 					time = this.sysres.getString("1#1 min|#{num} min");
9747 					break;
9748 				default:
9749 				case 'f':
9750 					time = this.sysres.getString("1#1 minute|#{num} minutes");
9751 					break;
9752 			}
9753 		} else if (diff < 1) {
9754 			num = Math.round(diff * 24);
9755 			switch (this.length) {
9756 				case 's':
9757 					time = this.sysres.getString("#{num}h");
9758 					break;
9759 				case 'm':
9760 					time = this.sysres.getString("1#1 hr|#{num} hrs", "durationMediumHours");
9761 					break;
9762 				case 'l':
9763 					time = this.sysres.getString("1#1 hr|#{num} hrs");
9764 					break;
9765 				default:
9766 				case 'f':
9767 					time = this.sysres.getString("1#1 hour|#{num} hours");
9768 					break;
9769 			}
9770 		} else if (diff < 14) {
9771 			num = Math.round(diff);
9772 			switch (this.length) {
9773 				case 's':
9774 					time = this.sysres.getString("#{num}d");
9775 					break;
9776 				case 'm':
9777 					time = this.sysres.getString("1#1 dy|#{num} dys");
9778 					break;
9779 				case 'l':
9780 					time = this.sysres.getString("1#1 day|#{num} days", "durationLongDays");
9781 					break;
9782 				default:
9783 				case 'f':
9784 					time = this.sysres.getString("1#1 day|#{num} days");
9785 					break;
9786 			}
9787 		} else if (diff < 84) {
9788 			num = Math.round(diff/7);
9789 			switch (this.length) {
9790 				case 's':
9791 					time = this.sysres.getString("#{num}w");
9792 					break;
9793 				case 'm':
9794 					time = this.sysres.getString("1#1 wk|#{num} wks", "durationMediumWeeks");
9795 					break;
9796 				case 'l':
9797 					time = this.sysres.getString("1#1 wk|#{num} wks");
9798 					break;
9799 				default:
9800 				case 'f':
9801 					time = this.sysres.getString("1#1 week|#{num} weeks");
9802 					break;
9803 			}
9804 		} else if (diff < 730) {
9805 			num = Math.round(diff/30.4);
9806 			switch (this.length) {
9807 				case 's':
9808 					time = this.sysres.getString("#{num}m", "durationShortMonths");
9809 					break;
9810 				case 'm':
9811 					time = this.sysres.getString("1#1 mo|#{num} mos");
9812 					break;
9813 				case 'l':
9814 					time = this.sysres.getString("1#1 mon|#{num} mons");
9815 					break;
9816 				default:
9817 				case 'f':
9818 					time = this.sysres.getString("1#1 month|#{num} months");
9819 					break;
9820 			}
9821 		} else {
9822 			num = Math.round(diff/365);
9823 			switch (this.length) {
9824 				case 's':
9825 					time = this.sysres.getString("#{num}y");
9826 					break;
9827 				case 'm':
9828 					time = this.sysres.getString("1#1 yr|#{num} yrs", "durationMediumYears");
9829 					break;
9830 				case 'l':
9831 					time = this.sysres.getString("1#1 yr|#{num} yrs");
9832 					break;
9833 				default:
9834 				case 'f':
9835 					time = this.sysres.getString("1#1 year|#{num} years");
9836 					break;
9837 			}
9838 		}
9839 		return fmt.format({duration: time.formatChoice(num, {num: num})});
9840 	}
9841 };
9842 
9843 
9844 
9845 /*< DateRngFmt.js */
9846 /*
9847  * DateFmt.js - Date formatter definition
9848  * 
9849  * Copyright © 2012-2015, JEDLSoft
9850  *
9851  * Licensed under the Apache License, Version 2.0 (the "License");
9852  * you may not use this file except in compliance with the License.
9853  * You may obtain a copy of the License at
9854  *
9855  *     http://www.apache.org/licenses/LICENSE-2.0
9856  *
9857  * Unless required by applicable law or agreed to in writing, software
9858  * distributed under the License is distributed on an "AS IS" BASIS,
9859  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9860  *
9861  * See the License for the specific language governing permissions and
9862  * limitations under the License.
9863  */
9864 
9865 /*
9866 !depends 
9867 ilib.js 
9868 Locale.js 
9869 IDate.js 
9870 IString.js 
9871 CalendarFactory.js
9872 LocaleInfo.js
9873 TimeZone.js
9874 DateFmt.js
9875 GregorianCal.js
9876 JSUtils.js
9877 Utils.js
9878 */
9879 
9880 // !data dateformats sysres
9881 
9882 
9883 
9884 
9885 
9886 /**
9887  * @class
9888  * Create a new date range formatter instance. The date range formatter is immutable once
9889  * it is created, but can format as many different date ranges as needed with the same
9890  * options. Create different date range formatter instances for different purposes
9891  * and then keep them cached for use later if you have more than one range to
9892  * format.<p>
9893  * 
9894  * The options may contain any of the following properties:
9895  * 
9896  * <ul>
9897  * <li><i>locale</i> - locale to use when formatting the date/times in the range. If the 
9898  * locale is not specified, then the default locale of the app or web page will be used.
9899  * 
9900  * <li><i>calendar</i> - the type of calendar to use for this format. The value should
9901  * be a sting containing the name of the calendar. Currently, the supported
9902  * types are "gregorian", "julian", "arabic", "hebrew", or "chinese". If the
9903  * calendar is not specified, then the default calendar for the locale is used. When the
9904  * calendar type is specified, then the format method must be called with an instance of
9905  * the appropriate date type. (eg. Gregorian calendar means that the format method must 
9906  * be called with a GregDate instance.)
9907  *  
9908  * <li><i>timezone</i> - time zone to use when formatting times. This may be a time zone
9909  * instance or a time zone specifier string in RFC 822 format. If not specified, the
9910  * default time zone for the locale is used.
9911  * 
9912  * <li><i>length</i> - Specify the length of the format to use as a string. The length 
9913  * is the approximate size of the formatted string.
9914  * 
9915  * <ul>
9916  * <li><i>short</i> - use a short representation of the time. This is the most compact format possible for the locale.
9917  * <li><i>medium</i> - use a medium length representation of the time. This is a slightly longer format.
9918  * <li><i>long</i> - use a long representation of the time. This is a fully specified format, but some of the textual 
9919  * components may still be abbreviated. (eg. "Tue" instead of "Tuesday")
9920  * <li><i>full</i> - use a full representation of the time. This is a fully specified format where all the textual 
9921  * components are spelled out completely.
9922  * </ul>
9923  * 
9924  * eg. The "short" format for an en_US range may be "MM/yy - MM/yy", whereas the long format might be 
9925  * "MMM, yyyy - MMM, yyyy". In the long format, the month name is textual instead of numeric 
9926  * and is longer, the year is 4 digits instead of 2, and the format contains slightly more 
9927  * spaces and formatting characters.<p>
9928  * 
9929  * Note that the length parameter does not specify which components are to be formatted. The
9930  * components that are formatted depend on the length of time in the range.
9931  * 
9932  * <li><i>clock</i> - specify that formatted times should use a 12 or 24 hour clock if the
9933  * format happens to include times. Valid values are "12" and "24".<p>
9934  * 
9935  * In some locales, both clocks are used. For example, in en_US, the general populace uses
9936  * a 12 hour clock with am/pm, but in the US military or in nautical or aeronautical or 
9937  * scientific writing, it is more common to use a 24 hour clock. This property allows you to
9938  * construct a formatter that overrides the default for the locale.<p>
9939  * 
9940  * If this property is not specified, the default is to use the most widely used convention
9941  * for the locale.
9942  * <li>onLoad - a callback function to call when the date range format object is fully 
9943  * loaded. When the onLoad option is given, the DateRngFmt object will attempt to
9944  * load any missing locale data using the ilib loader callback.
9945  * When the constructor is done (even if the data is already preassembled), the 
9946  * onLoad function is called with the current instance as a parameter, so this
9947  * callback can be used with preassembled or dynamic loading or a mix of the two. 
9948  * 
9949  * <li>sync - tell whether to load any missing locale data synchronously or 
9950  * asynchronously. If this option is given as "false", then the "onLoad"
9951  * callback must be given, as the instance returned from this constructor will
9952  * not be usable for a while.
9953  *  
9954  * <li><i>loadParams</i> - an object containing parameters to pass to the 
9955  * loader callback function when locale data is missing. The parameters are not
9956  * interpretted or modified in any way. They are simply passed along. The object 
9957  * may contain any property/value pairs as long as the calling code is in
9958  * agreement with the loader callback function as to what those parameters mean.
9959  * </ul>
9960  * <p>
9961  * 
9962  * 
9963  * @constructor
9964  * @param {Object} options options governing the way this date range formatter instance works
9965  */
9966 var DateRngFmt = function(options) {
9967 	var sync = true;
9968 	var loadParams = undefined;
9969 	this.locale = new Locale();
9970 	this.length = "s";
9971 	
9972 	if (options) {
9973 		if (options.locale) {
9974 			this.locale = (typeof(options.locale) === 'string') ? new Locale(options.locale) : options.locale;
9975 		}
9976 		
9977 		if (options.calendar) {
9978 			this.calName = options.calendar;
9979 		}
9980 		
9981 		if (options.length) {
9982 			if (options.length === 'short' ||
9983 				options.length === 'medium' ||
9984 				options.length === 'long' ||
9985 				options.length === 'full') {
9986 				// only use the first char to save space in the json files
9987 				this.length = options.length.charAt(0);
9988 			}
9989 		}
9990 		if (typeof(options.sync) !== 'undefined') {
9991 			sync = (options.sync == true);
9992 		}
9993 		
9994 		loadParams = options.loadParams;
9995 	}
9996 	
9997 	var opts = {};
9998 	JSUtils.shallowCopy(options, opts);
9999 	opts.sync = sync;
10000 	opts.loadParams = loadParams;
10001 	
10002 	/**
10003 	 * @private
10004 	 */
10005 	opts.onLoad = ilib.bind(this, function (fmt) {
10006 		this.dateFmt = fmt;
10007 		if (fmt) {
10008 			this.locinfo = this.dateFmt.locinfo;
10009 
10010 			// get the default calendar name from the locale, and if the locale doesn't define
10011 			// one, use the hard-coded gregorian as the last resort
10012 			this.calName = this.calName || this.locinfo.getCalendar() || "gregorian";
10013 			this.cal = CalendarFactory({
10014 				type: this.calName
10015 			});
10016 			if (!this.cal) {
10017 				this.cal = new GregorianCal();
10018 			}
10019 			
10020 			this.timeTemplate = this.dateFmt._getFormat(this.dateFmt.formats.time[this.dateFmt.clock], this.dateFmt.timeComponents, this.length) || "hh:mm";
10021 			this.timeTemplateArr = this.dateFmt._tokenize(this.timeTemplate);
10022 			
10023 			if (options && typeof(options.onLoad) === 'function') {
10024 				options.onLoad(this);
10025 			}
10026 		}
10027 	});
10028 
10029 	// delegate a bunch of the formatting to this formatter
10030 	new DateFmt(opts);
10031 };
10032 
10033 DateRngFmt.prototype = {
10034 	/**
10035 	 * Return the locale used with this formatter instance.
10036 	 * @return {Locale} the Locale instance for this formatter
10037 	 */
10038 	getLocale: function() {
10039 		return this.locale;
10040 	},
10041 	
10042 	/**
10043 	 * Return the name of the calendar used to format date/times for this
10044 	 * formatter instance.
10045 	 * @return {string} the name of the calendar used by this formatter
10046 	 */
10047 	getCalendar: function () {
10048 		return this.dateFmt.getCalendar();
10049 	},
10050 	
10051 	/**
10052 	 * Return the length used to format date/times in this formatter. This is either the
10053 	 * value of the length option to the constructor, or the default value.
10054 	 * 
10055 	 * @return {string} the length of formats this formatter returns
10056 	 */
10057 	getLength: function () {
10058 		return DateFmt.lenmap[this.length] || "";
10059 	},
10060 	
10061 	/**
10062 	 * Return the time zone used to format date/times for this formatter
10063 	 * instance.
10064 	 * @return {TimeZone} a string naming the time zone
10065 	 */
10066 	getTimeZone: function () {
10067 		return this.dateFmt.getTimeZone();
10068 	},
10069 	
10070 	/**
10071 	 * Return the clock option set in the constructor. If the clock option was
10072 	 * not given, the default from the locale is returned instead.
10073 	 * @return {string} "12" or "24" depending on whether this formatter uses
10074 	 * the 12-hour or 24-hour clock
10075 	 */
10076 	getClock: function () {
10077 		return this.dateFmt.getClock();
10078 	},
10079 	
10080 	/**
10081 	 * Format a date/time range according to the settings of the current
10082 	 * formatter. The range is specified as being from the "start" date until
10083 	 * the "end" date. <p>
10084 	 * 
10085 	 * The template that the date/time range uses depends on the
10086 	 * length of time between the dates, on the premise that a long date range
10087 	 * which is too specific is not useful. For example, when giving
10088 	 * the dates of the 100 Years War, in most situations it would be more 
10089 	 * appropriate to format the range as "1337 - 1453" than to format it as 
10090 	 * "10:37am November 9, 1337 - 4:37pm July 17, 1453", as the latter format 
10091 	 * is much too specific given the length of time that the range represents.
10092 	 * If a very specific, but long, date range really is needed, the caller 
10093 	 * should format two specific dates separately and put them 
10094 	 * together as you might with other normal strings.<p>
10095 	 * 
10096 	 * The format used for a date range contains the following date components,
10097 	 * where the order of those components is rearranged and the component values 
10098 	 * are translated according to each locale:
10099 	 * 
10100 	 * <ul>
10101 	 * <li>within 3 days: the times of day, dates, months, and years
10102 	 * <li>within 730 days (2 years): the dates, months, and years
10103 	 * <li>within 3650 days (10 years): the months and years
10104 	 * <li>longer than 10 years: the years only 
10105 	 * </ul>
10106 	 * 
10107 	 * In general, if any of the date components share a value between the
10108 	 * start and end date, that component is only given once. For example,
10109 	 * if the range is from November 15, 2011 to November 26, 2011, the 
10110 	 * start and end dates both share the same month and year. The 
10111 	 * range would then be formatted as "November 15-26, 2011". <p>
10112 	 * 
10113 	 * If you want to format a length of time instead of a particular range of
10114 	 * time (for example, the length of an event rather than the specific start time
10115 	 * and end time of that event), then use a duration formatter instance 
10116 	 * (DurationFmt) instead. The formatRange method will make sure that each component 
10117 	 * of the date/time is within the normal range for that component. For example, 
10118 	 * the minutes will always be between 0 and 59, no matter what is specified in 
10119 	 * the date to format, because that is the normal range for minutes. A duration 
10120 	 * format will allow the number of minutes to exceed 59. For example, if you 
10121 	 * were displaying the length of a movie that is 198 minutes long, the minutes
10122 	 * component of a duration could be 198.<p>
10123 	 * 
10124 	 * @param {IDate} start the starting date/time of the range. This must be of 
10125 	 * the same calendar type as the formatter itself. 
10126 	 * @param {IDate} end the ending date/time of the range. This must be of the 
10127 	 * same calendar type as the formatter itself.
10128 	 * @throws "Wrong calendar type" when the start or end dates are not the same
10129 	 * calendar type as the formatter itself
10130 	 * @return {string} a date range formatted for the locale
10131 	 */
10132 	format: function (start, end) {
10133 		var startRd, endRd, fmt = "", yearTemplate, monthTemplate, dayTemplate, formats;
10134 		
10135 		if (typeof(start) !== 'object' || !start.getCalendar || start.getCalendar() !== this.calName ||
10136 			typeof(end) !== 'object' || !end.getCalendar || end.getCalendar() !== this.calName) {
10137 			throw "Wrong calendar type";
10138 		}
10139 		
10140 		startRd = start.getRataDie();
10141 		endRd = end.getRataDie();
10142 		
10143 		// 
10144 		// legend:
10145 		// c00 - difference is less than 3 days. Year, month, and date are same, but time is different
10146 		// c01 - difference is less than 3 days. Year and month are same but date and time are different
10147 		// c02 - difference is less than 3 days. Year is same but month, date, and time are different. (ie. it straddles a month boundary)
10148 		// c03 - difference is less than 3 days. Year, month, date, and time are all different. (ie. it straddles a year boundary)
10149 		// c10 - difference is less than 2 years. Year and month are the same, but date is different.
10150 		// c11 - difference is less than 2 years. Year is the same, but month, date, and time are different.
10151 		// c12 - difference is less than 2 years. All fields are different. (ie. straddles a year boundary)
10152 		// c20 - difference is less than 10 years. All fields are different.
10153 		// c30 - difference is more than 10 years. All fields are different.
10154 		//
10155 		
10156 		if (endRd - startRd < 3) {
10157 			if (start.year === end.year) {
10158 				if (start.month === end.month) {
10159 					if (start.day === end.day) {
10160 						fmt = new IString(this.dateFmt._getFormat(this.dateFmt.formats.range, "c00", this.length));
10161 					} else {
10162 						fmt = new IString(this.dateFmt._getFormat(this.dateFmt.formats.range, "c01", this.length));
10163 					}
10164 				} else {
10165 					fmt = new IString(this.dateFmt._getFormat(this.dateFmt.formats.range, "c02", this.length));
10166 				}
10167 			} else {
10168 				fmt = new IString(this.dateFmt._getFormat(this.dateFmt.formats.range, "c03", this.length));
10169 			}
10170 		} else if (endRd - startRd < 730) {
10171 			if (start.year === end.year) {
10172 				if (start.month === end.month) {
10173 					fmt = new IString(this.dateFmt._getFormat(this.dateFmt.formats.range, "c10", this.length));
10174 				} else {
10175 					fmt = new IString(this.dateFmt._getFormat(this.dateFmt.formats.range, "c11", this.length));
10176 				}
10177 			} else {
10178 				fmt = new IString(this.dateFmt._getFormat(this.dateFmt.formats.range, "c12", this.length));
10179 			}
10180 		} else if (endRd - startRd < 3650) {
10181 			fmt = new IString(this.dateFmt._getFormat(this.dateFmt.formats.range, "c20", this.length));
10182 		} else {
10183 			fmt = new IString(this.dateFmt._getFormat(this.dateFmt.formats.range, "c30", this.length));
10184 		}
10185 
10186 		formats = this.dateFmt.formats.date;
10187 		yearTemplate = this.dateFmt._tokenize(this.dateFmt._getFormatInternal(formats, "y", this.length) || "yyyy");
10188 		monthTemplate = this.dateFmt._tokenize(this.dateFmt._getFormatInternal(formats, "m", this.length) || "MM");
10189 		dayTemplate = this.dateFmt._tokenize(this.dateFmt._getFormatInternal(formats, "d", this.length) || "dd");
10190 		
10191 		/*
10192 		console.log("fmt is " + fmt.toString());
10193 		console.log("year template is " + yearTemplate);
10194 		console.log("month template is " + monthTemplate);
10195 		console.log("day template is " + dayTemplate);
10196 		*/
10197 		
10198 		return fmt.format({
10199 			sy: this.dateFmt._formatTemplate(start, yearTemplate),
10200 			sm: this.dateFmt._formatTemplate(start, monthTemplate),
10201 			sd: this.dateFmt._formatTemplate(start, dayTemplate),
10202 			st: this.dateFmt._formatTemplate(start, this.timeTemplateArr),
10203 			ey: this.dateFmt._formatTemplate(end, yearTemplate),
10204 			em: this.dateFmt._formatTemplate(end, monthTemplate),
10205 			ed: this.dateFmt._formatTemplate(end, dayTemplate),
10206 			et: this.dateFmt._formatTemplate(end, this.timeTemplateArr)
10207 		});
10208 	}
10209 };
10210 
10211 
10212 /*< HebrewCal.js */
10213 /*
10214  * hebrew.js - Represent a Hebrew calendar object.
10215  * 
10216  * Copyright © 2012-2015, JEDLSoft
10217  *
10218  * Licensed under the Apache License, Version 2.0 (the "License");
10219  * you may not use this file except in compliance with the License.
10220  * You may obtain a copy of the License at
10221  *
10222  *     http://www.apache.org/licenses/LICENSE-2.0
10223  *
10224  * Unless required by applicable law or agreed to in writing, software
10225  * distributed under the License is distributed on an "AS IS" BASIS,
10226  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10227  *
10228  * See the License for the specific language governing permissions and
10229  * limitations under the License.
10230  */
10231 
10232 
10233 /* !depends ilib.js Calendar.js MathUtils.js */
10234 
10235 
10236 /**
10237  * @class
10238  * Construct a new Hebrew calendar object. This class encodes information about
10239  * the Hebrew (Jewish) calendar. The Hebrew calendar is a tabular hebrew 
10240  * calendar where the dates are calculated by arithmetic rules. This differs from 
10241  * the religious Hebrew calendar which is used to mark the beginning of particular 
10242  * holidays. The religious calendar depends on the first sighting of the new 
10243  * crescent moon to determine the first day of the new month. Because humans and 
10244  * weather are both involved, the actual time of sighting varies, so it is not 
10245  * really possible to precalculate the religious calendar. Certain groups, such 
10246  * as the Hebrew Society of North America, decreed in in 2007 that they will use
10247  * a calendar based on calculations rather than observations to determine the 
10248  * beginning of lunar months, and therefore the dates of holidays.<p>
10249  * 
10250  * 
10251  * @constructor
10252  * @extends Calendar
10253  */
10254 var HebrewCal = function() {
10255 	this.type = "hebrew";
10256 };
10257 
10258 /**
10259  * Return the number of days elapsed in the Hebrew calendar before the
10260  * given year starts.
10261  * @private
10262  * @param {number} year the year for which the number of days is sought
10263  * @return {number} the number of days elapsed in the Hebrew calendar before the
10264  * given year starts
10265  */
10266 HebrewCal.elapsedDays = function(year) {
10267 	var months = Math.floor(((235*year) - 234)/19);
10268 	var parts = 204 + 793 * MathUtils.mod(months, 1080);
10269 	var hours = 11 + 12 * months + 793 * Math.floor(months/1080) + 
10270 		Math.floor(parts/1080);
10271 	var days = 29 * months + Math.floor(hours/24);
10272 	return (MathUtils.mod(3 * (days + 1), 7) < 3) ? days + 1 : days;
10273 };
10274 
10275 /**
10276  * Return the number of days that the New Year's (Rosh HaShanah) in the Hebrew 
10277  * calendar will be corrected for the given year. Corrections are caused because New 
10278  * Year's is not allowed to start on certain days of the week. To deal with 
10279  * it, the start of the new year is corrected for the next year by adding a 
10280  * day to the 8th month (Heshvan) and/or the 9th month (Kislev) in the current
10281  * year to make them 30 days long instead of 29.
10282  * 
10283  * @private
10284  * @param {number} year the year for which the correction is sought
10285  * @param {number} elapsed number of days elapsed up to this year
10286  * @return {number} the number of days correction in the current year to make sure
10287  * Rosh HaShanah does not fall on undesirable days of the week
10288  */
10289 HebrewCal.newYearsCorrection = function(year, elapsed) {
10290 	var lastYear = HebrewCal.elapsedDays(year-1),
10291 		thisYear = elapsed,
10292 		nextYear = HebrewCal.elapsedDays(year+1);
10293 	
10294 	return (nextYear - thisYear) == 356 ? 2 : ((thisYear - lastYear) == 382 ? 1 : 0);
10295 };
10296 
10297 /**
10298  * Return the rata die date of the new year for the given hebrew year.
10299  * @private
10300  * @param {number} year the year for which the new year is needed
10301  * @return {number} the rata die date of the new year
10302  */
10303 HebrewCal.newYear = function(year) {
10304 	var elapsed = HebrewCal.elapsedDays(year); 
10305 	
10306 	return elapsed + HebrewCal.newYearsCorrection(year, elapsed);
10307 };
10308 
10309 /**
10310  * Return the number of days in the given year. Years contain a variable number of
10311  * days because the date of Rosh HaShanah (New Year's) changes so that it doesn't
10312  * fall on particular days of the week. Days are added to the months of Heshvan
10313  * and/or Kislev in the previous year in order to prevent the current year's New
10314  * Year from being on Sunday, Wednesday, or Friday.
10315  * 
10316  * @param {number} year the year for which the length is sought
10317  * @return {number} number of days in the given year
10318  */
10319 HebrewCal.daysInYear = function(year) {
10320 	return HebrewCal.newYear(year+1) - HebrewCal.newYear(year);
10321 };
10322 
10323 /**
10324  * Return true if the given year contains a long month of Heshvan. That is,
10325  * it is 30 days instead of 29.
10326  * 
10327  * @private
10328  * @param {number} year the year in which that month is questioned
10329  * @return {boolean} true if the given year contains a long month of Heshvan
10330  */
10331 HebrewCal.longHeshvan = function(year) {
10332 	return MathUtils.mod(HebrewCal.daysInYear(year), 10) === 5;
10333 };
10334 
10335 /**
10336  * Return true if the given year contains a long month of Kislev. That is,
10337  * it is 30 days instead of 29.
10338  * 
10339  * @private
10340  * @param {number} year the year in which that month is questioned
10341  * @return {boolean} true if the given year contains a short month of Kislev
10342  */
10343 HebrewCal.longKislev = function(year) {
10344 	return MathUtils.mod(HebrewCal.daysInYear(year), 10) !== 3;
10345 };
10346 
10347 /**
10348  * Return the date of the last day of the month for the given year. The date of
10349  * the last day of the month is variable because a number of months gain an extra 
10350  * day in leap years, and it is variable which months gain a day for each leap 
10351  * year and which do not.
10352  * 
10353  * @param {number} month the month for which the number of days is sought
10354  * @param {number} year the year in which that month is
10355  * @return {number} the number of days in the given month and year
10356  */
10357 HebrewCal.prototype.lastDayOfMonth = function(month, year) {
10358 	switch (month) {
10359 		case 2: 
10360 		case 4: 
10361 		case 6: 
10362 		case 10: 
10363 			return 29;
10364 		case 13:
10365 			return this.isLeapYear(year) ? 29 : 0;
10366 		case 8:
10367 			return HebrewCal.longHeshvan(year) ? 30 : 29;
10368 		case 9:
10369 			return HebrewCal.longKislev(year) ? 30 : 29;
10370 		case 12:
10371 		case 1:
10372 		case 3:
10373 		case 5:
10374 		case 7:
10375 		case 11:
10376 			return 30;
10377 		default:
10378 			return 0;
10379 	}
10380 };
10381 
10382 /**
10383  * Return the number of months in the given year. The number of months in a year varies
10384  * for luni-solar calendars because in some years, an extra month is needed to extend the 
10385  * days in a year to an entire solar year. The month is represented as a 1-based number
10386  * where 1=first month, 2=second month, etc.
10387  * 
10388  * @param {number} year a year for which the number of months is sought
10389  */
10390 HebrewCal.prototype.getNumMonths = function(year) {
10391 	return this.isLeapYear(year) ? 13 : 12;
10392 };
10393 
10394 /**
10395  * Return the number of days in a particular month in a particular year. This function
10396  * can return a different number for a month depending on the year because of leap years.
10397  *
10398  * @param {number} month the month for which the length is sought
10399  * @param {number} year the year within which that month can be found
10400  * @returns {number} the number of days within the given month in the given year, or
10401  * 0 for an invalid month in the year
10402  */
10403 HebrewCal.prototype.getMonLength = function(month, year) {
10404 	if (month < 1 || month > 13 || (month == 13 && !this.isLeapYear(year))) {
10405 		return 0;
10406 	}
10407 	return this.lastDayOfMonth(month, year);
10408 };
10409 
10410 /**
10411  * Return true if the given year is a leap year in the Hebrew calendar.
10412  * The year parameter may be given as a number, or as a HebrewDate object.
10413  * @param {number|Object} year the year for which the leap year information is being sought
10414  * @returns {boolean} true if the given year is a leap year
10415  */
10416 HebrewCal.prototype.isLeapYear = function(year) {
10417 	var y = (typeof(year) == 'number') ? year : year.year;
10418 	return (MathUtils.mod(1 + 7 * y, 19) < 7);
10419 };
10420 
10421 /**
10422  * Return the type of this calendar.
10423  * 
10424  * @returns {string} the name of the type of this calendar 
10425  */
10426 HebrewCal.prototype.getType = function() {
10427 	return this.type;
10428 };
10429 
10430 /**
10431  * Return a date instance for this calendar type using the given
10432  * options.
10433  * @param {Object} options options controlling the construction of 
10434  * the date instance
10435  * @returns {HebrewDate} a date appropriate for this calendar type
10436  * @deprecated Since 11.0.5. Use DateFactory({calendar: cal.getType(), ...}) instead
10437  */
10438 HebrewCal.prototype.newDateInstance = function (options) {
10439 		return new HebrewDate(options);
10440 };
10441 
10442 /*register this calendar for the factory method */
10443 Calendar._constructors["hebrew"] = HebrewCal;
10444 
10445 
10446 
10447 /*< HebrewRataDie.js */
10448 /*
10449  * HebrewRataDie.js - Represent an RD date in the Hebrew calendar
10450  * 
10451  * Copyright © 2012-2015, JEDLSoft
10452  *
10453  * Licensed under the Apache License, Version 2.0 (the "License");
10454  * you may not use this file except in compliance with the License.
10455  * You may obtain a copy of the License at
10456  *
10457  *     http://www.apache.org/licenses/LICENSE-2.0
10458  *
10459  * Unless required by applicable law or agreed to in writing, software
10460  * distributed under the License is distributed on an "AS IS" BASIS,
10461  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10462  *
10463  * See the License for the specific language governing permissions and
10464  * limitations under the License.
10465  */
10466 
10467 /* !depends 
10468 MathUtils.js
10469 HebrewCal.js
10470 RataDie.js
10471 */
10472 
10473 
10474 /**
10475  * @class
10476  * Construct a new Hebrew RD date number object. The constructor parameters can 
10477  * contain any of the following properties:
10478  * 
10479  * <ul>
10480  * <li><i>unixtime<i> - sets the time of this instance according to the given 
10481  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970.
10482  * 
10483  * <li><i>julianday</i> - sets the time of this instance according to the given
10484  * Julian Day instance or the Julian Day given as a float
10485  * 
10486  * <li><i>year</i> - any integer, including 0
10487  * 
10488  * <li><i>month</i> - 1 to 12, where 1 means January, 2 means February, etc.
10489  * 
10490  * <li><i>day</i> - 1 to 31
10491  * 
10492  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
10493  * is always done with an unambiguous 24 hour representation
10494  * 
10495  * <li><i>parts</i> - 0 to 1079. Specify the halaqim parts of an hour. Either specify 
10496  * the parts or specify the minutes, seconds, and milliseconds, but not both. 
10497  * 
10498  * <li><i>minute</i> - 0 to 59
10499  * 
10500  * <li><i>second</i> - 0 to 59
10501  * 
10502  * <li><i>millisecond</i> - 0 to 999
10503  * 
10504  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
10505  * </ul>
10506  *
10507  * If the constructor is called with another Hebrew date instance instead of
10508  * a parameter block, the other instance acts as a parameter block and its
10509  * settings are copied into the current instance.<p>
10510  * 
10511  * If the constructor is called with no arguments at all or if none of the 
10512  * properties listed above are present, then the RD is calculate based on 
10513  * the current date at the time of instantiation. <p>
10514  * 
10515  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
10516  * specified in the params, it is assumed that they have the smallest possible
10517  * value in the range for the property (zero or one).<p>
10518  * 
10519  * 
10520  * @private
10521  * @constructor
10522  * @extends RataDie
10523  * @param {Object=} params parameters that govern the settings and behaviour of this Hebrew RD date
10524  */
10525 var HebrewRataDie = function(params) {
10526 	this.cal = params && params.cal || new HebrewCal();
10527 	this.rd = NaN;
10528 	RataDie.call(this, params);
10529 };
10530 
10531 HebrewRataDie.prototype = new RataDie();
10532 HebrewRataDie.prototype.parent = RataDie;
10533 HebrewRataDie.prototype.constructor = HebrewRataDie;
10534 
10535 /**
10536  * The difference between a zero Julian day and the first day of the Hebrew 
10537  * calendar: sunset on Monday, Tishri 1, 1 = September 7, 3760 BC Gregorian = JD 347997.25
10538  * @private
10539  * @type number
10540  */
10541 HebrewRataDie.prototype.epoch = 347997.25;
10542 
10543 /**
10544  * the cumulative lengths of each month for a non-leap year, without new years corrections
10545  * @private
10546  * @const
10547  * @type Array.<number>
10548  */
10549 HebrewRataDie.cumMonthLengths = [
10550 	176,  /* Nisan */
10551 	206,  /* Iyyar */
10552 	235,  /* Sivan */
10553 	265,  /* Tammuz */
10554 	294,  /* Av */
10555 	324,  /* Elul */
10556 	0,    /* Tishri - Jewish New Year (Rosh HaShanah) starts in month 7 */
10557 	30,   /* Heshvan */
10558 	59,   /* Kislev */
10559 	88,   /* Teveth */
10560 	117,  /* Shevat */
10561 	147   /* Adar I */
10562 ];
10563 
10564 /**
10565  * the cumulative lengths of each month for a leap year, without new years corrections 
10566  * @private
10567  * @const
10568  * @type Array.<number>
10569  */
10570 HebrewRataDie.cumMonthLengthsLeap = [
10571 	206,  /* Nisan */
10572 	236,  /* Iyyar */
10573 	265,  /* Sivan */
10574 	295,  /* Tammuz */
10575 	324,  /* Av */
10576 	354,  /* Elul */
10577 	0,    /* Tishri - Jewish New Year (Rosh HaShanah) starts in month 7 */
10578 	30,   /* Heshvan */
10579 	59,   /* Kislev */
10580 	88,   /* Teveth */
10581 	117,  /* Shevat */
10582 	147,  /* Adar I */
10583 	177   /* Adar II */
10584 ];
10585 
10586 /**
10587  * Calculate the Rata Die (fixed day) number of the given date from the
10588  * date components.
10589  * 
10590  * @private
10591  * @param {Object} date the date components to calculate the RD from
10592  */
10593 HebrewRataDie.prototype._setDateComponents = function(date) {
10594 	var elapsed = HebrewCal.elapsedDays(date.year);
10595 	var days = elapsed +
10596 		HebrewCal.newYearsCorrection(date.year, elapsed) +
10597 		date.day - 1;
10598 	var sum = 0, table;
10599 	
10600 	//console.log("getRataDie: converting " +  JSON.stringify(date));
10601 	//console.log("getRataDie: days is " +  days);
10602 	//console.log("getRataDie: new years correction is " +  HebrewCal.newYearsCorrection(date.year, elapsed));
10603 	
10604 	table = this.cal.isLeapYear(date.year) ? 
10605 		HebrewRataDie.cumMonthLengthsLeap :
10606 		HebrewRataDie.cumMonthLengths;
10607 	sum = table[date.month-1];
10608 	
10609 	// gets cumulative without correction, so now add in the correction
10610 	if ((date.month < 7 || date.month > 8) && HebrewCal.longHeshvan(date.year)) {
10611 		sum++;
10612 	}
10613 	if ((date.month < 7 || date.month > 9) && HebrewCal.longKislev(date.year)) {
10614 		sum++;
10615 	}
10616 	// console.log("getRataDie: cum days is now " +  sum);
10617 	
10618 	days += sum;
10619 	
10620 	// the date starts at sunset, which we take as 18:00, so the hours from
10621 	// midnight to 18:00 are on the current Gregorian day, and the hours from
10622 	// 18:00 to midnight are on the previous Gregorian day. So to calculate the 
10623 	// number of hours into the current day that this time represents, we have
10624 	// to count from 18:00 to midnight first, and add in 6 hours if the time is
10625 	// less than 18:00
10626 	var minute, second, millisecond;
10627 	
10628 	if (typeof(date.parts) !== 'undefined') {
10629 		// The parts (halaqim) of the hour. This can be a number from 0 to 1079.
10630 		var parts = parseInt(date.parts, 10);
10631 		var seconds = parseInt(parts, 10) * 3.333333333333;
10632 		minute = Math.floor(seconds / 60);
10633 		seconds -= minute * 60;
10634 		second = Math.floor(seconds);
10635 		millisecond = (seconds - second);	
10636 	} else {
10637 		minute = parseInt(date.minute, 10) || 0;
10638 		second = parseInt(date.second, 10) || 0;
10639 		millisecond = parseInt(date.millisecond, 10) || 0;
10640 	}
10641 		
10642 	var time;
10643 	if (date.hour >= 18) {
10644 		time = ((date.hour - 18 || 0) * 3600000 +
10645 			(minute || 0) * 60000 +
10646 			(second || 0) * 1000 +
10647 			(millisecond || 0)) / 
10648 			86400000;
10649 	} else {
10650 		time = 0.25 +	// 6 hours from 18:00 to midnight on the previous gregorian day
10651 				((date.hour || 0) * 3600000 +
10652 				(minute || 0) * 60000 +
10653 				(second || 0) * 1000 +
10654 				(millisecond || 0)) / 
10655 				86400000;
10656 	}
10657 	
10658 	//console.log("getRataDie: rd is " +  (days + time));
10659 	this.rd = days + time;
10660 };
10661 	
10662 /**
10663  * Return the rd number of the particular day of the week on or before the 
10664  * given rd. eg. The Sunday on or before the given rd.
10665  * @private
10666  * @param {number} rd the rata die date of the reference date
10667  * @param {number} dayOfWeek the day of the week that is being sought relative 
10668  * to the current date
10669  * @return {number} the rd of the day of the week
10670  */
10671 HebrewRataDie.prototype._onOrBefore = function(rd, dayOfWeek) {
10672 	return rd - MathUtils.mod(Math.floor(rd) - dayOfWeek + 1, 7);
10673 };
10674 
10675 
10676 
10677 /*< HebrewDate.js */
10678 /*
10679  * HebrewDate.js - Represent a date in the Hebrew calendar
10680  * 
10681  * Copyright © 2012-2015, JEDLSoft
10682  *
10683  * Licensed under the Apache License, Version 2.0 (the "License");
10684  * you may not use this file except in compliance with the License.
10685  * You may obtain a copy of the License at
10686  *
10687  *     http://www.apache.org/licenses/LICENSE-2.0
10688  *
10689  * Unless required by applicable law or agreed to in writing, software
10690  * distributed under the License is distributed on an "AS IS" BASIS,
10691  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10692  *
10693  * See the License for the specific language governing permissions and
10694  * limitations under the License.
10695  */
10696 
10697 /* !depends 
10698 ilib.js
10699 Locale.js
10700 LocaleInfo.js
10701 TimeZone.js
10702 IDate.js
10703 MathUtils.js
10704 Calendar.js
10705 HebrewCal.js
10706 HebrewRataDie.js
10707 */
10708 
10709 
10710 
10711 
10712 /**
10713  * @class
10714  * Construct a new civil Hebrew date object. The constructor can be called
10715  * with a params object that can contain the following properties:<p>
10716  * 
10717  * <ul>
10718  * <li><i>julianday</i> - the Julian Day to set into this date
10719  * <li><i>year</i> - any integer except 0. Years go from -1 (BCE) to 1 (CE), skipping the zero year
10720  * <li><i>month</i> - 1 to 12, where 1 means Nisan, 2 means Iyyar, etc.
10721  * <li><i>day</i> - 1 to 30
10722  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
10723  * is always done with an unambiguous 24 hour representation
10724  * <li><i>parts</i> - 0 to 1079. Specify the halaqim parts of an hour. Either specify 
10725  * the parts or specify the minutes, seconds, and milliseconds, but not both. 
10726  * <li><i>minute</i> - 0 to 59
10727  * <li><i>second</i> - 0 to 59
10728  * <li><i>millisecond</i> - 0 to 999
10729  * <li><i>locale</i> - the TimeZone instance or time zone name as a string 
10730  * of this julian date. The date/time is kept in the local time. The time zone
10731  * is used later if this date is formatted according to a different time zone and
10732  * the difference has to be calculated, or when the date format has a time zone
10733  * component in it.
10734  * <li><i>timezone</i> - the time zone of this instance. If the time zone is not 
10735  * given, it can be inferred from this locale. For locales that span multiple
10736  * time zones, the one with the largest population is chosen as the one that 
10737  * represents the locale. 
10738  * 
10739  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
10740  * </ul>
10741  * 
10742  * If called with another Hebrew date argument, the date components of the given
10743  * date are copied into the current one.<p>
10744  * 
10745  * If the constructor is called with no arguments at all or if none of the 
10746  * properties listed above 
10747  * from <i>julianday</i> through <i>millisecond</i> are present, then the date 
10748  * components are 
10749  * filled in with the current date at the time of instantiation. Note that if
10750  * you do not give the time zone when defaulting to the current time and the 
10751  * time zone for all of ilib was not set with <i>ilib.setTimeZone()</i>, then the
10752  * time zone will default to UTC ("Universal Time, Coordinated" or "Greenwich 
10753  * Mean Time").<p>
10754  * 
10755  * 
10756  * @constructor
10757  * @extends IDate
10758  * @param {Object=} params parameters that govern the settings and behaviour of this Hebrew date
10759  */
10760 var HebrewDate = function(params) {
10761 	this.cal = new HebrewCal();
10762 	
10763 	if (params) {
10764 		if (params.timezone) {
10765 			this.timezone = params.timezone;
10766 		}
10767 		if (params.locale) {
10768 			this.locale = (typeof(params.locale) === 'string') ? new Locale(params.locale) : params.locale;
10769 			if (!this.timezone) {
10770 				var li = new LocaleInfo(this.locale);
10771 				this.timezone = li.getTimeZone(); 
10772 			}
10773 		}
10774 
10775 		if (params.year || params.month || params.day || params.hour ||
10776 				params.minute || params.second || params.millisecond || params.parts ) {
10777 			/**
10778 			 * Year in the Hebrew calendar.
10779 			 * @type number
10780 			 */
10781 			this.year = parseInt(params.year, 10) || 0;
10782 
10783 			/**
10784 			 * The month number, ranging from 1 to 13.
10785 			 * @type number
10786 			 */
10787 			this.month = parseInt(params.month, 10) || 1;
10788 
10789 			/**
10790 			 * The day of the month. This ranges from 1 to 30.
10791 			 * @type number
10792 			 */
10793 			this.day = parseInt(params.day, 10) || 1;
10794 			
10795 			/**
10796 			 * The hour of the day. This can be a number from 0 to 23, as times are
10797 			 * stored unambiguously in the 24-hour clock.
10798 			 * @type number
10799 			 */
10800 			this.hour = parseInt(params.hour, 10) || 0;
10801 
10802 			if (typeof(params.parts) !== 'undefined') {
10803 				/**
10804 				 * The parts (halaqim) of the hour. This can be a number from 0 to 1079.
10805 				 * @type number
10806 				 */
10807 				this.parts = parseInt(params.parts, 10);
10808 				var seconds = parseInt(params.parts, 10) * 3.333333333333;
10809 				this.minute = Math.floor(seconds / 60);
10810 				seconds -= this.minute * 60;
10811 				this.second = Math.floor(seconds);
10812 				this.millisecond = (seconds - this.second);	
10813 			} else {
10814 				/**
10815 				 * The minute of the hours. Ranges from 0 to 59.
10816 				 * @type number
10817 				 */
10818 				this.minute = parseInt(params.minute, 10) || 0;
10819 	
10820 				/**
10821 				 * The second of the minute. Ranges from 0 to 59.
10822 				 * @type number
10823 				 */
10824 				this.second = parseInt(params.second, 10) || 0;
10825 	
10826 				/**
10827 				 * The millisecond of the second. Ranges from 0 to 999.
10828 				 * @type number
10829 				 */
10830 				this.millisecond = parseInt(params.millisecond, 10) || 0;
10831 			}
10832 				
10833 			/**
10834 			 * The day of the year. Ranges from 1 to 383.
10835 			 * @type number
10836 			 */
10837 			this.dayOfYear = parseInt(params.dayOfYear, 10);
10838 			
10839 			if (typeof(params.dst) === 'boolean') {
10840 				this.dst = params.dst;
10841 			}
10842 			
10843 			this.rd = this.newRd(this);
10844 			
10845 			// add the time zone offset to the rd to convert to UTC
10846 			if (!this.tz) {
10847 				this.tz = new TimeZone({id: this.timezone});
10848 			}
10849 			// getOffsetMillis requires that this.year, this.rd, and this.dst 
10850 			// are set in order to figure out which time zone rules apply and 
10851 			// what the offset is at that point in the year
10852 			this.offset = this.tz._getOffsetMillisWallTime(this) / 86400000;
10853 			if (this.offset !== 0) {
10854 				this.rd = this.newRd({
10855 					rd: this.rd.getRataDie() - this.offset
10856 				});
10857 			}
10858 		}
10859 	} 
10860 	
10861 	if (!this.rd) {
10862 		this.rd = this.newRd(params);
10863 		this._calcDateComponents();
10864 	}
10865 };
10866 
10867 HebrewDate.prototype = new IDate({noinstance: true});
10868 HebrewDate.prototype.parent = IDate;
10869 HebrewDate.prototype.constructor = HebrewDate;
10870 
10871 /**
10872  * the cumulative lengths of each month for a non-leap year, without new years corrections,
10873  * that can be used in reverse to map days to months
10874  * @private
10875  * @const
10876  * @type Array.<number>
10877  */
10878 HebrewDate.cumMonthLengthsReverse = [
10879 //  [days, monthnumber],                                                
10880 	[0,   7],  /* Tishri - Jewish New Year (Rosh HaShanah) starts in month 7 */
10881 	[30,  8],  /* Heshvan */
10882 	[59,  9],  /* Kislev */
10883 	[88,  10], /* Teveth */
10884 	[117, 11], /* Shevat */
10885 	[147, 12], /* Adar I */
10886 	[176, 1],  /* Nisan */
10887 	[206, 2],  /* Iyyar */
10888 	[235, 3],  /* Sivan */
10889 	[265, 4],  /* Tammuz */
10890 	[294, 5],  /* Av */
10891 	[324, 6],  /* Elul */
10892 	[354, 7]   /* end of year sentinel value */
10893 ];
10894 
10895 /**
10896  * the cumulative lengths of each month for a leap year, without new years corrections
10897  * that can be used in reverse to map days to months 
10898  * 
10899  * @private
10900  * @const
10901  * @type Array.<number>
10902  */
10903 HebrewDate.cumMonthLengthsLeapReverse = [
10904 //  [days, monthnumber],                                                
10905 	[0,   7],  /* Tishri - Jewish New Year (Rosh HaShanah) starts in month 7 */
10906 	[30,  8],  /* Heshvan */
10907 	[59,  9],  /* Kislev */
10908 	[88,  10], /* Teveth */
10909 	[117, 11], /* Shevat */
10910 	[147, 12], /* Adar I */
10911 	[177, 13], /* Adar II */
10912 	[206, 1],  /* Nisan */
10913 	[236, 2],  /* Iyyar */
10914 	[265, 3],  /* Sivan */
10915 	[295, 4],  /* Tammuz */
10916 	[324, 5],  /* Av */
10917 	[354, 6],  /* Elul */
10918 	[384, 7]   /* end of year sentinel value */
10919 ];
10920 
10921 /**
10922  * Number of days difference between RD 0 of the Hebrew calendar 
10923  * (Jan 1, 1 Gregorian = JD 1721057.5) and RD 0 of the Hebrew calendar
10924  * (September 7, -3760 Gregorian = JD 347997.25)
10925  * @private
10926  * @const
10927  * @type number
10928  */
10929 HebrewDate.GregorianDiff = 1373060.25;
10930 
10931 /**
10932  * Return a new RD for this date type using the given params.
10933  * @private
10934  * @param {Object=} params the parameters used to create this rata die instance
10935  * @returns {RataDie} the new RD instance for the given params
10936  */
10937 HebrewDate.prototype.newRd = function (params) {
10938 	return new HebrewRataDie(params);
10939 };
10940 
10941 /**
10942  * Return the year for the given RD
10943  * @protected
10944  * @param {number} rd RD to calculate from 
10945  * @returns {number} the year for the RD
10946  */
10947 HebrewDate.prototype._calcYear = function(rd) {
10948 	var year, approximation, nextNewYear;
10949 	
10950 	// divide by the average number of days per year in the Hebrew calendar
10951 	// to approximate the year, then tweak it to get the real year
10952 	approximation = Math.floor(rd / 365.246822206) + 1;
10953 	
10954 	// console.log("HebrewDate._calcYear: approx is " + approximation);
10955 	
10956 	// search forward from approximation-1 for the year that actually contains this rd
10957 	year = approximation;
10958 	nextNewYear = HebrewCal.newYear(year);
10959 	while (rd >= nextNewYear) {
10960 		year++;
10961 		nextNewYear = HebrewCal.newYear(year);
10962 	}
10963 	return year - 1;
10964 };
10965 
10966 /**
10967  * Calculate date components for the given RD date.
10968  * @protected
10969  */
10970 HebrewDate.prototype._calcDateComponents = function () {
10971 	var remainder,
10972 		i,
10973 		table,
10974 		target,
10975 		rd = this.rd.getRataDie();
10976 	
10977 	// console.log("HebrewDate.calcComponents: calculating for rd " + rd);
10978 
10979 	if (typeof(this.offset) === "undefined") {
10980 		this.year = this._calcYear(rd);
10981 		
10982 		// now offset the RD by the time zone, then recalculate in case we were 
10983 		// near the year boundary
10984 		if (!this.tz) {
10985 			this.tz = new TimeZone({id: this.timezone});
10986 		}
10987 		this.offset = this.tz.getOffsetMillis(this) / 86400000;
10988 	}
10989 
10990 	if (this.offset !== 0) {
10991 		rd += this.offset;
10992 		this.year = this._calcYear(rd);
10993 	}
10994 	
10995 	// console.log("HebrewDate.calcComponents: year is " + this.year + " with starting rd " + thisNewYear);
10996 	
10997 	remainder = rd - HebrewCal.newYear(this.year);
10998 	// console.log("HebrewDate.calcComponents: remainder is " + remainder);
10999 
11000 	// take out new years corrections so we get the right month when we look it up in the table
11001 	if (remainder >= 59) {
11002 		if (remainder >= 88) {
11003 			if (HebrewCal.longKislev(this.year)) {
11004 				remainder--;
11005 			}
11006 		}
11007 		if (HebrewCal.longHeshvan(this.year)) {
11008 			remainder--;
11009 		}
11010 	}
11011 	
11012 	// console.log("HebrewDate.calcComponents: after new years corrections, remainder is " + remainder);
11013 	
11014 	table = this.cal.isLeapYear(this.year) ? 
11015 			HebrewDate.cumMonthLengthsLeapReverse :
11016 			HebrewDate.cumMonthLengthsReverse;
11017 	
11018 	i = 0;
11019 	target = Math.floor(remainder);
11020 	while (i+1 < table.length && target >= table[i+1][0]) {
11021 		i++;
11022 	}
11023 	
11024 	this.month = table[i][1];
11025 	// console.log("HebrewDate.calcComponents: remainder is " + remainder);
11026 	remainder -= table[i][0];
11027 	
11028 	// console.log("HebrewDate.calcComponents: month is " + this.month + " and remainder is " + remainder);
11029 	
11030 	this.day = Math.floor(remainder);
11031 	remainder -= this.day;
11032 	this.day++; // days are 1-based
11033 	
11034 	// console.log("HebrewDate.calcComponents: day is " + this.day + " and remainder is " + remainder);
11035 
11036 	// now convert to milliseconds for the rest of the calculation
11037 	remainder = Math.round(remainder * 86400000);
11038 	
11039 	this.hour = Math.floor(remainder/3600000);
11040 	remainder -= this.hour * 3600000;
11041 	
11042 	// the hours from 0 to 6 are actually 18:00 to midnight of the previous
11043 	// gregorian day, so we have to adjust for that
11044 	if (this.hour >= 6) {
11045 		this.hour -= 6;
11046 	} else {
11047 		this.hour += 18;
11048 	}
11049 		
11050 	this.minute = Math.floor(remainder/60000);
11051 	remainder -= this.minute * 60000;
11052 	
11053 	this.second = Math.floor(remainder/1000);
11054 	remainder -= this.second * 1000;
11055 	
11056 	this.millisecond = Math.floor(remainder);
11057 };
11058 
11059 /**
11060  * Return the day of the week of this date. The day of the week is encoded
11061  * as number from 0 to 6, with 0=Sunday, 1=Monday, etc., until 6=Saturday.
11062  * 
11063  * @return {number} the day of the week
11064  */
11065 HebrewDate.prototype.getDayOfWeek = function() {
11066 	var rd = Math.floor(this.rd.getRataDie() + (this.offset || 0));
11067 	return MathUtils.mod(rd+1, 7);
11068 };
11069 
11070 /**
11071  * Get the Halaqim (parts) of an hour. There are 1080 parts in an hour, which means
11072  * each part is 3.33333333 seconds long. This means the number returned may not
11073  * be an integer.
11074  * 
11075  * @return {number} the halaqim parts of the current hour
11076  */
11077 HebrewDate.prototype.getHalaqim = function() {
11078 	if (this.parts < 0) {
11079 		// convert to ms first, then to parts
11080 		var h = this.minute * 60000 + this.second * 1000 + this.millisecond;
11081 		this.parts = (h * 0.0003);
11082 	}
11083 	return this.parts;
11084 };
11085 
11086 /**
11087  * Return the rd number of the first Sunday of the given ISO year.
11088  * @protected
11089  * @return the rd of the first Sunday of the ISO year
11090  */
11091 HebrewDate.prototype.firstSunday = function (year) {
11092 	var tishri1 = this.newRd({
11093 		year: year,
11094 		month: 7,
11095 		day: 1,
11096 		hour: 18,
11097 		minute: 0,
11098 		second: 0,
11099 		millisecond: 0,
11100 		cal: this.cal
11101 	});
11102 	var firstThu = this.newRd({
11103 		rd: tishri1.onOrAfter(4),
11104 		cal: this.cal
11105 	});
11106 	return firstThu.before(0);
11107 };
11108 
11109 /**
11110  * Return the ordinal day of the year. Days are counted from 1 and proceed linearly up to 
11111  * 385, regardless of months or weeks, etc. That is, Tishri 1st is day 1, and 
11112  * Elul 29 is 385 for a leap year with a long Heshvan and long Kislev.
11113  * @return {number} the ordinal day of the year
11114  */
11115 HebrewDate.prototype.getDayOfYear = function() {
11116 	var table = this.cal.isLeapYear(this.year) ? 
11117 				HebrewRataDie.cumMonthLengthsLeap : 
11118 				HebrewRataDie.cumMonthLengths;
11119 	var days = table[this.month-1];
11120 	if ((this.month < 7 || this.month > 8) && HebrewCal.longHeshvan(this.year)) {
11121 		days++;
11122 	}
11123 	if ((this.month < 7 || this.month > 9) && HebrewCal.longKislev(this.year)) {
11124 		days++;
11125 	}
11126 
11127 	return days + this.day;
11128 };
11129 
11130 /**
11131  * Return the ordinal number of the week within the month. The first week of a month is
11132  * the first one that contains 4 or more days in that month. If any days precede this
11133  * first week, they are marked as being in week 0. This function returns values from 0
11134  * through 6.<p>
11135  * 
11136  * The locale is a required parameter because different locales that use the same 
11137  * Hebrew calendar consider different days of the week to be the beginning of
11138  * the week. This can affect the week of the month in which some days are located.
11139  * 
11140  * @param {Locale|string} locale the locale or locale spec to use when figuring out 
11141  * the first day of the week
11142  * @return {number} the ordinal number of the week within the current month
11143  */
11144 HebrewDate.prototype.getWeekOfMonth = function(locale) {
11145 	var li = new LocaleInfo(locale),
11146 		first = this.newRd({
11147 			year: this.year,
11148 			month: this.month,
11149 			day: 1,
11150 			hour: 18,
11151 			minute: 0,
11152 			second: 0,
11153 			millisecond: 0
11154 		}),
11155 		rd = this.rd.getRataDie(),
11156 		weekStart = first.onOrAfter(li.getFirstDayOfWeek());
11157 	
11158 	if (weekStart - first.getRataDie() > 3) {
11159 		// if the first week has 4 or more days in it of the current month, then consider
11160 		// that week 1. Otherwise, it is week 0. To make it week 1, move the week start
11161 		// one week earlier.
11162 		weekStart -= 7;
11163 	}
11164 	return (rd < weekStart) ? 0 : Math.floor((rd - weekStart) / 7) + 1;
11165 };
11166 
11167 /**
11168  * Return the era for this date as a number. The value for the era for Hebrew 
11169  * calendars is -1 for "before the Hebrew era" and 1 for "the Hebrew era". 
11170  * Hebrew era dates are any date after Tishri 1, 1, which is the same as
11171  * September 7, 3760 BC in the Gregorian calendar. 
11172  * 
11173  * @return {number} 1 if this date is in the Hebrew era, -1 if it is before the 
11174  * Hebrew era 
11175  */
11176 HebrewDate.prototype.getEra = function() {
11177 	return (this.year < 1) ? -1 : 1;
11178 };
11179 
11180 /**
11181  * Return the name of the calendar that governs this date.
11182  * 
11183  * @return {string} a string giving the name of the calendar
11184  */
11185 HebrewDate.prototype.getCalendar = function() {
11186 	return "hebrew";
11187 };
11188 
11189 // register with the factory method
11190 IDate._constructors["hebrew"] = HebrewDate;
11191 
11192 
11193 
11194 /*< IslamicCal.js */
11195 /*
11196  * islamic.js - Represent a Islamic calendar object.
11197  * 
11198  * Copyright © 2012-2015, JEDLSoft
11199  *
11200  * Licensed under the Apache License, Version 2.0 (the "License");
11201  * you may not use this file except in compliance with the License.
11202  * You may obtain a copy of the License at
11203  *
11204  *     http://www.apache.org/licenses/LICENSE-2.0
11205  *
11206  * Unless required by applicable law or agreed to in writing, software
11207  * distributed under the License is distributed on an "AS IS" BASIS,
11208  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11209  *
11210  * See the License for the specific language governing permissions and
11211  * limitations under the License.
11212  */
11213 
11214 
11215 /* !depends 
11216 ilib.js
11217 Calendar.js 
11218 MathUtils.js 
11219 */
11220 
11221 
11222 /**
11223  * @class
11224  * Construct a new Islamic calendar object. This class encodes information about
11225  * the civil Islamic calendar. The civil Islamic calendar is a tabular islamic 
11226  * calendar where the dates are calculated by arithmetic rules. This differs from 
11227  * the religious Islamic calendar which is used to mark the beginning of particular 
11228  * holidays. The religious calendar depends on the first sighting of the new 
11229  * crescent moon to determine the first day of the new month. Because humans and 
11230  * weather are both involved, the actual time of sighting varies, so it is not 
11231  * really possible to precalculate the religious calendar. Certain groups, such 
11232  * as the Islamic Society of North America, decreed in in 2007 that they will use
11233  * a calendar based on calculations rather than observations to determine the 
11234  * beginning of lunar months, and therefore the dates of holidays.<p>
11235  * 
11236  * 
11237  * @constructor
11238  * @extends Calendar
11239  */
11240 var IslamicCal = function() {
11241 	this.type = "islamic";
11242 };
11243 
11244 /**
11245  * the lengths of each month 
11246  * @private
11247  * @const
11248  * @type Array.<number>
11249  */
11250 IslamicCal.monthLengths = [
11251 	30,  /* Muharram */
11252 	29,  /* Saffar */
11253 	30,  /* Rabi'I */
11254 	29,  /* Rabi'II */
11255 	30,  /* Jumada I */
11256 	29,  /* Jumada II */
11257 	30,  /* Rajab */
11258 	29,  /* Sha'ban */
11259 	30,  /* Ramadan */
11260 	29,  /* Shawwal */
11261 	30,  /* Dhu al-Qa'da */
11262 	29   /* Dhu al-Hijja */
11263 ];
11264 
11265 
11266 /**
11267  * Return the number of months in the given year. The number of months in a year varies
11268  * for luni-solar calendars because in some years, an extra month is needed to extend the 
11269  * days in a year to an entire solar year. The month is represented as a 1-based number
11270  * where 1=first month, 2=second month, etc.
11271  * 
11272  * @param {number} year a year for which the number of months is sought
11273  */
11274 IslamicCal.prototype.getNumMonths = function(year) {
11275 	return 12;
11276 };
11277 
11278 /**
11279  * Return the number of days in a particular month in a particular year. This function
11280  * can return a different number for a month depending on the year because of things
11281  * like leap years.
11282  *
11283  * @param {number} month the month for which the length is sought
11284  * @param {number} year the year within which that month can be found
11285  * @return {number} the number of days within the given month in the given year
11286  */
11287 IslamicCal.prototype.getMonLength = function(month, year) {
11288 	if (month !== 12) {
11289 		return IslamicCal.monthLengths[month-1];
11290 	} else {
11291 		return this.isLeapYear(year) ? 30 : 29;
11292 	}
11293 };
11294 
11295 /**
11296  * Return true if the given year is a leap year in the Islamic calendar.
11297  * The year parameter may be given as a number, or as a IslamicDate object.
11298  * @param {number} year the year for which the leap year information is being sought
11299  * @return {boolean} true if the given year is a leap year
11300  */
11301 IslamicCal.prototype.isLeapYear = function(year) {
11302 	return (MathUtils.mod((14 + 11 * year), 30) < 11);
11303 };
11304 
11305 /**
11306  * Return the type of this calendar.
11307  * 
11308  * @return {string} the name of the type of this calendar 
11309  */
11310 IslamicCal.prototype.getType = function() {
11311 	return this.type;
11312 };
11313 
11314 /**
11315  * Return a date instance for this calendar type using the given
11316  * options.
11317  * @param {Object} options options controlling the construction of 
11318  * the date instance
11319  * @return {IslamicDate} a date appropriate for this calendar type
11320  * @deprecated Since 11.0.5. Use DateFactory({calendar: cal.getType(), ...}) instead
11321  */
11322 IslamicCal.prototype.newDateInstance = function (options) {
11323 		return new IslamicDate(options);
11324 };
11325 
11326 /*register this calendar for the factory method */
11327 Calendar._constructors["islamic"] = IslamicCal;
11328 
11329 
11330 /*< IslamicRataDie.js */
11331 /*
11332  * IslamicRataDie.js - Represent an RD date in the Islamic calendar
11333  * 
11334  * Copyright © 2012-2015, JEDLSoft
11335  *
11336  * Licensed under the Apache License, Version 2.0 (the "License");
11337  * you may not use this file except in compliance with the License.
11338  * You may obtain a copy of the License at
11339  *
11340  *     http://www.apache.org/licenses/LICENSE-2.0
11341  *
11342  * Unless required by applicable law or agreed to in writing, software
11343  * distributed under the License is distributed on an "AS IS" BASIS,
11344  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11345  *
11346  * See the License for the specific language governing permissions and
11347  * limitations under the License.
11348  */
11349 
11350 /* !depends 
11351 IslamicCal.js
11352 RataDie.js
11353 */
11354 
11355 
11356 /**
11357  * @class
11358  * Construct a new Islamic RD date number object. The constructor parameters can 
11359  * contain any of the following properties:
11360  * 
11361  * <ul>
11362  * <li><i>unixtime<i> - sets the time of this instance according to the given 
11363  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970.
11364  * 
11365  * <li><i>julianday</i> - sets the time of this instance according to the given
11366  * Julian Day instance or the Julian Day given as a float
11367  * 
11368  * <li><i>year</i> - any integer, including 0
11369  * 
11370  * <li><i>month</i> - 1 to 12, where 1 means January, 2 means February, etc.
11371  * 
11372  * <li><i>day</i> - 1 to 31
11373  * 
11374  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
11375  * is always done with an unambiguous 24 hour representation
11376  * 
11377  * <li><i>minute</i> - 0 to 59
11378  * 
11379  * <li><i>second</i> - 0 to 59
11380  * 
11381  * <li><i>millisecond</i> - 0 to 999
11382  * 
11383  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
11384  * </ul>
11385  *
11386  * If the constructor is called with another Islamic date instance instead of
11387  * a parameter block, the other instance acts as a parameter block and its
11388  * settings are copied into the current instance.<p>
11389  * 
11390  * If the constructor is called with no arguments at all or if none of the 
11391  * properties listed above are present, then the RD is calculate based on 
11392  * the current date at the time of instantiation. <p>
11393  * 
11394  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
11395  * specified in the params, it is assumed that they have the smallest possible
11396  * value in the range for the property (zero or one).<p>
11397  * 
11398  * 
11399  * @private
11400  * @constructor
11401  * @extends RataDie
11402  * @param {Object=} params parameters that govern the settings and behaviour of this Islamic RD date
11403  */
11404 var IslamicRataDie = function(params) {
11405 	this.cal = params && params.cal || new IslamicCal();
11406 	this.rd = NaN;
11407 	RataDie.call(this, params);
11408 };
11409 
11410 IslamicRataDie.prototype = new RataDie();
11411 IslamicRataDie.prototype.parent = RataDie;
11412 IslamicRataDie.prototype.constructor = IslamicRataDie;
11413 
11414 /**
11415  * The difference between a zero Julian day and the first Islamic date
11416  * of Friday, July 16, 622 CE Julian. 
11417  * @private
11418  * @type number
11419  */
11420 IslamicRataDie.prototype.epoch = 1948439.5;
11421 
11422 /**
11423  * Calculate the Rata Die (fixed day) number of the given date from the
11424  * date components.
11425  *
11426  * @protected
11427  * @param {Object} date the date components to calculate the RD from
11428  */
11429 IslamicRataDie.prototype._setDateComponents = function(date) {
11430 	var days = (date.year - 1) * 354 +
11431 		Math.ceil(29.5 * (date.month - 1)) +
11432 		date.day +
11433 		Math.floor((3 + 11 * date.year) / 30) - 1;
11434 	var time = (date.hour * 3600000 +
11435 		date.minute * 60000 +
11436 		date.second * 1000 +
11437 		date.millisecond) / 
11438 		86400000; 
11439 	
11440 	//console.log("getRataDie: converting " +  JSON.stringify(date));
11441 	//console.log("getRataDie: days is " +  days);
11442 	//console.log("getRataDie: time is " +  time);
11443 	//console.log("getRataDie: rd is " +  (days + time));
11444 
11445 	this.rd = days + time;
11446 };
11447 	
11448 
11449 /*< IslamicDate.js */
11450 /*
11451  * islamicDate.js - Represent a date in the Islamic calendar
11452  * 
11453  * Copyright © 2012-2015, JEDLSoft
11454  *
11455  * Licensed under the Apache License, Version 2.0 (the "License");
11456  * you may not use this file except in compliance with the License.
11457  * You may obtain a copy of the License at
11458  *
11459  *     http://www.apache.org/licenses/LICENSE-2.0
11460  *
11461  * Unless required by applicable law or agreed to in writing, software
11462  * distributed under the License is distributed on an "AS IS" BASIS,
11463  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11464  *
11465  * See the License for the specific language governing permissions and
11466  * limitations under the License.
11467  */
11468 
11469 /* !depends 
11470 ilib.js
11471 Locale.js
11472 LocaleInfo.js
11473 TimeZone.js
11474 IDate.js
11475 MathUtils.js
11476 SearchUtils.js
11477 Calendar.js
11478 IslamicCal.js
11479 IslamicRataDie.js
11480 */
11481 
11482 
11483 
11484 
11485 /**
11486  * @class
11487  * Construct a new civil Islamic date object. The constructor can be called
11488  * with a params object that can contain the following properties:<p>
11489  * 
11490  * <ul>
11491  * <li><i>julianday</i> - the Julian Day to set into this date
11492  * <li><i>year</i> - any integer except 0. Years go from -1 (BCE) to 1 (CE), skipping the zero year
11493  * <li><i>month</i> - 1 to 12, where 1 means Muharram, 2 means Saffar, etc.
11494  * <li><i>day</i> - 1 to 30
11495  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
11496  * is always done with an unambiguous 24 hour representation
11497  * <li><i>minute</i> - 0 to 59
11498  * <li><i>second</i> - 0 to 59
11499  * <li><i>millisecond</i> - 0 to 999
11500  * <li><i>locale</i> - the TimeZone instance or time zone name as a string 
11501  * of this julian date. The date/time is kept in the local time. The time zone
11502  * is used later if this date is formatted according to a different time zone and
11503  * the difference has to be calculated, or when the date format has a time zone
11504  * component in it.
11505  * <li><i>timezone</i> - the time zone of this instance. If the time zone is not 
11506  * given, it can be inferred from this locale. For locales that span multiple
11507  * time zones, the one with the largest population is chosen as the one that 
11508  * represents the locale. 
11509  * 
11510  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
11511  * </ul>
11512  * 
11513  * If called with another Islamic date argument, the date components of the given
11514  * date are copied into the current one.<p>
11515  * 
11516  * If the constructor is called with no arguments at all or if none of the 
11517  * properties listed above 
11518  * from <i>julianday</i> through <i>millisecond</i> are present, then the date 
11519  * components are 
11520  * filled in with the current date at the time of instantiation. Note that if
11521  * you do not give the time zone when defaulting to the current time and the 
11522  * time zone for all of ilib was not set with <i>ilib.setTimeZone()</i>, then the
11523  * time zone will default to UTC ("Universal Time, Coordinated" or "Greenwich 
11524  * Mean Time").<p>
11525  * 
11526  * 
11527  * @constructor
11528  * @extends IDate
11529  * @param {Object=} params parameters that govern the settings and behaviour of this Islamic date
11530  */
11531 var IslamicDate = function(params) {
11532 	this.cal = new IslamicCal();
11533 	
11534 	if (params) {
11535 		if (params.locale) {
11536 			this.locale = (typeof(params.locale) === 'string') ? new Locale(params.locale) : params.locale;
11537 			var li = new LocaleInfo(this.locale);
11538 			this.timezone = li.getTimeZone(); 
11539 		}
11540 		if (params.timezone) {
11541 			this.timezone = params.timezone;
11542 		}
11543 		
11544 		if (params.year || params.month || params.day || params.hour ||
11545 				params.minute || params.second || params.millisecond ) {
11546 			/**
11547 			 * Year in the Islamic calendar.
11548 			 * @type number
11549 			 */
11550 			this.year = parseInt(params.year, 10) || 0;
11551 
11552 			/**
11553 			 * The month number, ranging from 1 to 12 (December).
11554 			 * @type number
11555 			 */
11556 			this.month = parseInt(params.month, 10) || 1;
11557 
11558 			/**
11559 			 * The day of the month. This ranges from 1 to 30.
11560 			 * @type number
11561 			 */
11562 			this.day = parseInt(params.day, 10) || 1;
11563 			
11564 			/**
11565 			 * The hour of the day. This can be a number from 0 to 23, as times are
11566 			 * stored unambiguously in the 24-hour clock.
11567 			 * @type number
11568 			 */
11569 			this.hour = parseInt(params.hour, 10) || 0;
11570 
11571 			/**
11572 			 * The minute of the hours. Ranges from 0 to 59.
11573 			 * @type number
11574 			 */
11575 			this.minute = parseInt(params.minute, 10) || 0;
11576 
11577 			/**
11578 			 * The second of the minute. Ranges from 0 to 59.
11579 			 * @type number
11580 			 */
11581 			this.second = parseInt(params.second, 10) || 0;
11582 
11583 			/**
11584 			 * The millisecond of the second. Ranges from 0 to 999.
11585 			 * @type number
11586 			 */
11587 			this.millisecond = parseInt(params.millisecond, 10) || 0;
11588 			
11589 			/**
11590 			 * The day of the year. Ranges from 1 to 355.
11591 			 * @type number
11592 			 */
11593 			this.dayOfYear = parseInt(params.dayOfYear, 10);
11594 
11595 			if (typeof(params.dst) === 'boolean') {
11596 				this.dst = params.dst;
11597 			}
11598 			
11599 			this.rd = this.newRd(this);
11600 			
11601 			// add the time zone offset to the rd to convert to UTC
11602 			if (!this.tz) {
11603 				this.tz = new TimeZone({id: this.timezone});
11604 			}
11605 			// getOffsetMillis requires that this.year, this.rd, and this.dst 
11606 			// are set in order to figure out which time zone rules apply and 
11607 			// what the offset is at that point in the year
11608 			this.offset = this.tz._getOffsetMillisWallTime(this) / 86400000;
11609 			if (this.offset !== 0) {
11610 				this.rd = this.newRd({
11611 					rd: this.rd.getRataDie() - this.offset
11612 				});
11613 			}
11614 		}
11615 	}
11616 
11617 	if (!this.rd) {
11618 		this.rd = this.newRd(params);
11619 		this._calcDateComponents();
11620 	}
11621 };
11622 
11623 IslamicDate.prototype = new IDate({noinstance: true});
11624 IslamicDate.prototype.parent = IDate;
11625 IslamicDate.prototype.constructor = IslamicDate;
11626 
11627 /**
11628  * the cumulative lengths of each month, for a non-leap year 
11629  * @private
11630  * @const
11631  * @type Array.<number>
11632  */
11633 IslamicDate.cumMonthLengths = [
11634 	0,  /* Muharram */
11635 	30,  /* Saffar */
11636 	59,  /* Rabi'I */
11637 	89,  /* Rabi'II */
11638 	118,  /* Jumada I */
11639 	148,  /* Jumada II */
11640 	177,  /* Rajab */
11641 	207,  /* Sha'ban */
11642 	236,  /* Ramadan */
11643 	266,  /* Shawwal */
11644 	295,  /* Dhu al-Qa'da */
11645 	325,  /* Dhu al-Hijja */
11646 	354
11647 ];
11648 
11649 /**
11650  * Number of days difference between RD 0 of the Gregorian calendar and
11651  * RD 0 of the Islamic calendar. 
11652  * @private
11653  * @const
11654  * @type number
11655  */
11656 IslamicDate.GregorianDiff = 227015;
11657 
11658 /**
11659  * Return a new RD for this date type using the given params.
11660  * @protected
11661  * @param {Object=} params the parameters used to create this rata die instance
11662  * @returns {RataDie} the new RD instance for the given params
11663  */
11664 IslamicDate.prototype.newRd = function (params) {
11665 	return new IslamicRataDie(params);
11666 };
11667 
11668 /**
11669  * Return the year for the given RD
11670  * @protected
11671  * @param {number} rd RD to calculate from 
11672  * @returns {number} the year for the RD
11673  */
11674 IslamicDate.prototype._calcYear = function(rd) {
11675 	return Math.floor((30 * rd + 10646) / 10631);
11676 };
11677 
11678 /**
11679  * Calculate date components for the given RD date.
11680  * @protected
11681  */
11682 IslamicDate.prototype._calcDateComponents = function () {
11683 	var remainder,
11684 		rd = this.rd.getRataDie();
11685 	
11686 	this.year = this._calcYear(rd);
11687 
11688 	if (typeof(this.offset) === "undefined") {
11689 		this.year = this._calcYear(rd);
11690 		
11691 		// now offset the RD by the time zone, then recalculate in case we were 
11692 		// near the year boundary
11693 		if (!this.tz) {
11694 			this.tz = new TimeZone({id: this.timezone});
11695 		}
11696 		this.offset = this.tz.getOffsetMillis(this) / 86400000;
11697 	}
11698 
11699 	if (this.offset !== 0) {
11700 		rd += this.offset;
11701 		this.year = this._calcYear(rd);
11702 	}
11703 
11704 	//console.log("IslamicDate.calcComponent: calculating for rd " + rd);
11705 	//console.log("IslamicDate.calcComponent: year is " + ret.year);
11706 	var yearStart = this.newRd({
11707 		year: this.year,
11708 		month: 1,
11709 		day: 1,
11710 		hour: 0,
11711 		minute: 0,
11712 		second: 0,
11713 		millisecond: 0
11714 	});
11715 	remainder = rd - yearStart.getRataDie() + 1;
11716 	
11717 	this.dayOfYear = remainder;
11718 	
11719 	//console.log("IslamicDate.calcComponent: remainder is " + remainder);
11720 	
11721 	this.month = SearchUtils.bsearch(remainder, IslamicDate.cumMonthLengths);
11722 	remainder -= IslamicDate.cumMonthLengths[this.month-1];
11723 
11724 	//console.log("IslamicDate.calcComponent: month is " + this.month + " and remainder is " + remainder);
11725 	
11726 	this.day = Math.floor(remainder);
11727 	remainder -= this.day;
11728 
11729 	//console.log("IslamicDate.calcComponent: day is " + this.day + " and remainder is " + remainder);
11730 
11731 	// now convert to milliseconds for the rest of the calculation
11732 	remainder = Math.round(remainder * 86400000);
11733 	
11734 	this.hour = Math.floor(remainder/3600000);
11735 	remainder -= this.hour * 3600000;
11736 	
11737 	this.minute = Math.floor(remainder/60000);
11738 	remainder -= this.minute * 60000;
11739 	
11740 	this.second = Math.floor(remainder/1000);
11741 	remainder -= this.second * 1000;
11742 	
11743 	this.millisecond = remainder;
11744 };
11745 
11746 /**
11747  * Return the day of the week of this date. The day of the week is encoded
11748  * as number from 0 to 6, with 0=Sunday, 1=Monday, etc., until 6=Saturday.
11749  * 
11750  * @return {number} the day of the week
11751  */
11752 IslamicDate.prototype.getDayOfWeek = function() {
11753 	var rd = Math.floor(this.rd.getRataDie() + (this.offset || 0));
11754 	return MathUtils.mod(rd-2, 7);
11755 };
11756 
11757 /**
11758  * Return the ordinal day of the year. Days are counted from 1 and proceed linearly up to 
11759  * 354 or 355, regardless of months or weeks, etc. That is, Muharran 1st is day 1, and 
11760  * Dhu al-Hijja 29 is 354.
11761  * @return {number} the ordinal day of the year
11762  */
11763 IslamicDate.prototype.getDayOfYear = function() {
11764 	return IslamicDate.cumMonthLengths[this.month-1] + this.day;
11765 };
11766 
11767 /**
11768  * Return the era for this date as a number. The value for the era for Islamic 
11769  * calendars is -1 for "before the Islamic era" and 1 for "the Islamic era". 
11770  * Islamic era dates are any date after Muharran 1, 1, which is the same as
11771  * July 16, 622 CE in the Gregorian calendar. 
11772  * 
11773  * @return {number} 1 if this date is in the common era, -1 if it is before the 
11774  * common era 
11775  */
11776 IslamicDate.prototype.getEra = function() {
11777 	return (this.year < 1) ? -1 : 1;
11778 };
11779 
11780 /**
11781  * Return the name of the calendar that governs this date.
11782  * 
11783  * @return {string} a string giving the name of the calendar
11784  */
11785 IslamicDate.prototype.getCalendar = function() {
11786 	return "islamic";
11787 };
11788 
11789 //register with the factory method
11790 IDate._constructors["islamic"] = IslamicDate;
11791 
11792 
11793 /*< JulianCal.js */
11794 /*
11795  * julian.js - Represent a Julian calendar object.
11796  * 
11797  * Copyright © 2012-2015, JEDLSoft
11798  *
11799  * Licensed under the Apache License, Version 2.0 (the "License");
11800  * you may not use this file except in compliance with the License.
11801  * You may obtain a copy of the License at
11802  *
11803  *     http://www.apache.org/licenses/LICENSE-2.0
11804  *
11805  * Unless required by applicable law or agreed to in writing, software
11806  * distributed under the License is distributed on an "AS IS" BASIS,
11807  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11808  *
11809  * See the License for the specific language governing permissions and
11810  * limitations under the License.
11811  */
11812 
11813 
11814 /* !depends ilib.js Calendar.js MathUtils.js */
11815 
11816 
11817 /**
11818  * @class
11819  * Construct a new Julian calendar object. This class encodes information about
11820  * a Julian calendar.<p>
11821  * 
11822  * 
11823  * @constructor
11824  * @extends Calendar
11825  */
11826 var JulianCal = function() {
11827 	this.type = "julian";
11828 };
11829 
11830 /* the lengths of each month */
11831 JulianCal.monthLengths = [
11832 	31,  /* Jan */
11833 	28,  /* Feb */
11834 	31,  /* Mar */
11835 	30,  /* Apr */
11836 	31,  /* May */
11837 	30,  /* Jun */
11838 	31,  /* Jul */
11839 	31,  /* Aug */
11840 	30,  /* Sep */
11841 	31,  /* Oct */
11842 	30,  /* Nov */
11843 	31   /* Dec */
11844 ];
11845 
11846 /**
11847  * the cumulative lengths of each month, for a non-leap year 
11848  * @private
11849  * @const
11850  * @type Array.<number>
11851  */
11852 JulianCal.cumMonthLengths = [
11853     0,   /* Jan */
11854 	31,  /* Feb */
11855 	59,  /* Mar */
11856 	90,  /* Apr */
11857 	120, /* May */
11858 	151, /* Jun */
11859 	181, /* Jul */
11860 	212, /* Aug */
11861 	243, /* Sep */
11862 	273, /* Oct */
11863 	304, /* Nov */
11864 	334, /* Dec */
11865 	365
11866 ];
11867 
11868 /**
11869  * the cumulative lengths of each month, for a leap year 
11870  * @private
11871  * @const
11872  * @type Array.<number>
11873  */
11874 JulianCal.cumMonthLengthsLeap = [
11875 	0,   /* Jan */
11876 	31,  /* Feb */
11877 	60,  /* Mar */
11878 	91,  /* Apr */
11879 	121, /* May */
11880 	152, /* Jun */
11881 	182, /* Jul */
11882 	213, /* Aug */
11883 	244, /* Sep */
11884 	274, /* Oct */
11885 	305, /* Nov */
11886 	335, /* Dec */
11887 	366
11888 ];
11889 
11890 /**
11891  * Return the number of months in the given year. The number of months in a year varies
11892  * for lunar calendars because in some years, an extra month is needed to extend the 
11893  * days in a year to an entire solar year. The month is represented as a 1-based number
11894  * where 1=Jaunary, 2=February, etc. until 12=December.
11895  * 
11896  * @param {number} year a year for which the number of months is sought
11897  */
11898 JulianCal.prototype.getNumMonths = function(year) {
11899 	return 12;
11900 };
11901 
11902 /**
11903  * Return the number of days in a particular month in a particular year. This function
11904  * can return a different number for a month depending on the year because of things
11905  * like leap years.
11906  * 
11907  * @param {number} month the month for which the length is sought
11908  * @param {number} year the year within which that month can be found
11909  * @return {number} the number of days within the given month in the given year
11910  */
11911 JulianCal.prototype.getMonLength = function(month, year) {
11912 	if (month !== 2 || !this.isLeapYear(year)) {
11913 		return JulianCal.monthLengths[month-1];
11914 	} else {
11915 		return 29;
11916 	}
11917 };
11918 
11919 /**
11920  * Return true if the given year is a leap year in the Julian calendar.
11921  * The year parameter may be given as a number, or as a JulDate object.
11922  * @param {number|JulianDate} year the year for which the leap year information is being sought
11923  * @return {boolean} true if the given year is a leap year
11924  */
11925 JulianCal.prototype.isLeapYear = function(year) {
11926 	var y = (typeof(year) === 'number' ? year : year.year);
11927 	return MathUtils.mod(y, 4) === ((year > 0) ? 0 : 3);
11928 };
11929 
11930 /**
11931  * Return the type of this calendar.
11932  * 
11933  * @return {string} the name of the type of this calendar 
11934  */
11935 JulianCal.prototype.getType = function() {
11936 	return this.type;
11937 };
11938 
11939 /**
11940  * Return a date instance for this calendar type using the given
11941  * options.
11942  * @param {Object} options options controlling the construction of 
11943  * the date instance
11944  * @return {IDate} a date appropriate for this calendar type
11945  * @deprecated Since 11.0.5. Use DateFactory({calendar: cal.getType(), ...}) instead
11946  */
11947 JulianCal.prototype.newDateInstance = function (options) {
11948 		return new JulianDate(options);
11949 };
11950 
11951 /* register this calendar for the factory method */
11952 Calendar._constructors["julian"] = JulianCal;
11953 
11954 
11955 /*< JulianRataDie.js */
11956 /*
11957  * julianDate.js - Represent a date in the Julian calendar
11958  * 
11959  * Copyright © 2012-2015, JEDLSoft
11960  *
11961  * Licensed under the Apache License, Version 2.0 (the "License");
11962  * you may not use this file except in compliance with the License.
11963  * You may obtain a copy of the License at
11964  *
11965  *     http://www.apache.org/licenses/LICENSE-2.0
11966  *
11967  * Unless required by applicable law or agreed to in writing, software
11968  * distributed under the License is distributed on an "AS IS" BASIS,
11969  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11970  *
11971  * See the License for the specific language governing permissions and
11972  * limitations under the License.
11973  */
11974 
11975 /* !depends 
11976 JulianCal.js 
11977 RataDie.js
11978 */
11979 
11980 
11981 /**
11982  * @class
11983  * Construct a new Julian RD date number object. The constructor parameters can 
11984  * contain any of the following properties:
11985  * 
11986  * <ul>
11987  * <li><i>unixtime<i> - sets the time of this instance according to the given 
11988  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970.
11989  * 
11990  * <li><i>julianday</i> - sets the time of this instance according to the given
11991  * Julian Day instance or the Julian Day given as a float
11992  * 
11993  * <li><i>year</i> - any integer, including 0
11994  * 
11995  * <li><i>month</i> - 1 to 12, where 1 means January, 2 means February, etc.
11996  * 
11997  * <li><i>day</i> - 1 to 31
11998  * 
11999  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
12000  * is always done with an unambiguous 24 hour representation
12001  * 
12002  * <li><i>minute</i> - 0 to 59
12003  * 
12004  * <li><i>second</i> - 0 to 59
12005  * 
12006  * <li><i>millisecond</i> - 0 to 999
12007  * 
12008  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
12009  * </ul>
12010  *
12011  * If the constructor is called with another Julian date instance instead of
12012  * a parameter block, the other instance acts as a parameter block and its
12013  * settings are copied into the current instance.<p>
12014  * 
12015  * If the constructor is called with no arguments at all or if none of the 
12016  * properties listed above are present, then the RD is calculate based on 
12017  * the current date at the time of instantiation. <p>
12018  * 
12019  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
12020  * specified in the params, it is assumed that they have the smallest possible
12021  * value in the range for the property (zero or one).<p>
12022  * 
12023  * 
12024  * @private
12025  * @constructor
12026  * @extends RataDie
12027  * @param {Object=} params parameters that govern the settings and behaviour of this Julian RD date
12028  */
12029 var JulianRataDie = function(params) {
12030 	this.cal = params && params.cal || new JulianCal();
12031 	this.rd = NaN;
12032 	RataDie.call(this, params);
12033 };
12034 
12035 JulianRataDie.prototype = new RataDie();
12036 JulianRataDie.prototype.parent = RataDie;
12037 JulianRataDie.prototype.constructor = JulianRataDie;
12038 
12039 /**
12040  * The difference between a zero Julian day and the first Julian date
12041  * of Friday, July 16, 622 CE Julian. 
12042  * @private
12043  * @type number
12044  */
12045 JulianRataDie.prototype.epoch = 1721422.5;
12046 
12047 /**
12048  * Calculate the Rata Die (fixed day) number of the given date from the
12049  * date components.
12050  * 
12051  * @protected
12052  * @param {Object} date the date components to calculate the RD from
12053  */
12054 JulianRataDie.prototype._setDateComponents = function(date) {
12055 	var year = date.year + ((date.year < 0) ? 1 : 0);
12056 	var years = 365 * (year - 1) + Math.floor((year-1)/4);
12057 	var dayInYear = (date.month > 1 ? JulianCal.cumMonthLengths[date.month-1] : 0) +
12058 		date.day +
12059 		(this.cal.isLeapYear(date.year) && date.month > 2 ? 1 : 0);
12060 	var rdtime = (date.hour * 3600000 +
12061 		date.minute * 60000 +
12062 		date.second * 1000 +
12063 		date.millisecond) / 
12064 		86400000;
12065 	
12066 	/*
12067 	console.log("calcRataDie: converting " +  JSON.stringify(parts));
12068 	console.log("getRataDie: year is " +  years);
12069 	console.log("getRataDie: day in year is " +  dayInYear);
12070 	console.log("getRataDie: rdtime is " +  rdtime);
12071 	console.log("getRataDie: rd is " +  (years + dayInYear + rdtime));
12072 	*/
12073 	
12074 	this.rd = years + dayInYear + rdtime;
12075 };
12076 
12077 
12078 /*< JulianDate.js */
12079 /*
12080  * JulianDate.js - Represent a date in the Julian calendar
12081  * 
12082  * Copyright © 2012-2015, JEDLSoft
12083  *
12084  * Licensed under the Apache License, Version 2.0 (the "License");
12085  * you may not use this file except in compliance with the License.
12086  * You may obtain a copy of the License at
12087  *
12088  *     http://www.apache.org/licenses/LICENSE-2.0
12089  *
12090  * Unless required by applicable law or agreed to in writing, software
12091  * distributed under the License is distributed on an "AS IS" BASIS,
12092  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12093  *
12094  * See the License for the specific language governing permissions and
12095  * limitations under the License.
12096  */
12097 
12098 /* !depends 
12099 ilib.js
12100 Locale.js
12101 IDate.js 
12102 TimeZone.js
12103 Calendar.js 
12104 JulianCal.js 
12105 SearchUtils.js 
12106 MathUtils.js
12107 LocaleInfo.js 
12108 JulianRataDie.js
12109 */
12110 
12111 
12112 
12113 
12114 /**
12115  * @class
12116  * Construct a new date object for the Julian Calendar. The constructor can be called
12117  * with a parameter object that contains any of the following properties:
12118  * 
12119  * <ul>
12120  * <li><i>unixtime<i> - sets the time of this instance according to the given 
12121  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970 (Gregorian).
12122  * <li><i>julianday</i> - the Julian Day to set into this date
12123  * <li><i>year</i> - any integer except 0. Years go from -1 (BCE) to 1 (CE), skipping the zero 
12124  * year which doesn't exist in the Julian calendar
12125  * <li><i>month</i> - 1 to 12, where 1 means January, 2 means February, etc.
12126  * <li><i>day</i> - 1 to 31
12127  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
12128  * is always done with an unambiguous 24 hour representation
12129  * <li><i>minute</i> - 0 to 59
12130  * <li><i>second</i> - 0 to 59
12131  * <li><i>millisecond<i> - 0 to 999
12132  * <li><i>locale</i> - the TimeZone instance or time zone name as a string 
12133  * of this julian date. The date/time is kept in the local time. The time zone
12134  * is used later if this date is formatted according to a different time zone and
12135  * the difference has to be calculated, or when the date format has a time zone
12136  * component in it.
12137  * <li><i>timezone</i> - the time zone of this instance. If the time zone is not 
12138  * given, it can be inferred from this locale. For locales that span multiple
12139  * time zones, the one with the largest population is chosen as the one that 
12140  * represents the locale. 
12141  * 
12142  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
12143  * </ul>
12144  * 
12145  * NB. The <a href="http://en.wikipedia.org/wiki/Julian_date">Julian Day</a> 
12146  * (JulianDay) object is a <i>different</i> object than a 
12147  * <a href="http://en.wikipedia.org/wiki/Julian_calendar">date in
12148  * the Julian calendar</a> and the two are not to be confused. The Julian Day 
12149  * object represents time as a number of whole and fractional days since the 
12150  * beginning of the epoch, whereas a date in the Julian 
12151  * calendar is a regular date that signifies year, month, day, etc. using the rules
12152  * of the Julian calendar. The naming of Julian Days and the Julian calendar are
12153  * unfortunately close, and come from history.<p>
12154  *  
12155  * If called with another Julian date argument, the date components of the given
12156  * date are copied into the current one.<p>
12157  * 
12158  * If the constructor is called with no arguments at all or if none of the 
12159  * properties listed above 
12160  * from <i>unixtime</i> through <i>millisecond</i> are present, then the date 
12161  * components are 
12162  * filled in with the current date at the time of instantiation. Note that if
12163  * you do not give the time zone when defaulting to the current time and the 
12164  * time zone for all of ilib was not set with <i>ilib.setTimeZone()</i>, then the
12165  * time zone will default to UTC ("Universal Time, Coordinated" or "Greenwich 
12166  * Mean Time").<p>
12167  * 
12168  * 
12169  * @constructor
12170  * @extends IDate
12171  * @param {Object=} params parameters that govern the settings and behaviour of this Julian date
12172  */
12173 var JulianDate = function(params) {
12174 	this.cal = new JulianCal();
12175 	
12176 	if (params) {
12177 		if (params.locale) {
12178 			this.locale = (typeof(params.locale) === 'string') ? new Locale(params.locale) : params.locale;
12179 			var li = new LocaleInfo(this.locale);
12180 			this.timezone = li.getTimeZone(); 
12181 		}
12182 		if (params.timezone) {
12183 			this.timezone = params.timezone;
12184 		}
12185 		
12186 		if (params.year || params.month || params.day || params.hour ||
12187 				params.minute || params.second || params.millisecond ) {
12188 			/**
12189 			 * Year in the Julian calendar.
12190 			 * @type number
12191 			 */
12192 			this.year = parseInt(params.year, 10) || 0;
12193 			/**
12194 			 * The month number, ranging from 1 (January) to 12 (December).
12195 			 * @type number
12196 			 */
12197 			this.month = parseInt(params.month, 10) || 1;
12198 			/**
12199 			 * The day of the month. This ranges from 1 to 31.
12200 			 * @type number
12201 			 */
12202 			this.day = parseInt(params.day, 10) || 1;
12203 			/**
12204 			 * The hour of the day. This can be a number from 0 to 23, as times are
12205 			 * stored unambiguously in the 24-hour clock.
12206 			 * @type number
12207 			 */
12208 			this.hour = parseInt(params.hour, 10) || 0;
12209 			/**
12210 			 * The minute of the hours. Ranges from 0 to 59.
12211 			 * @type number
12212 			 */
12213 			this.minute = parseInt(params.minute, 10) || 0;
12214 			/**
12215 			 * The second of the minute. Ranges from 0 to 59.
12216 			 * @type number
12217 			 */
12218 			this.second = parseInt(params.second, 10) || 0;
12219 			/**
12220 			 * The millisecond of the second. Ranges from 0 to 999.
12221 			 * @type number
12222 			 */
12223 			this.millisecond = parseInt(params.millisecond, 10) || 0;
12224 			
12225 			/**
12226 			 * The day of the year. Ranges from 1 to 383.
12227 			 * @type number
12228 			 */
12229 			this.dayOfYear = parseInt(params.dayOfYear, 10);
12230 			
12231 			if (typeof(params.dst) === 'boolean') {
12232 				this.dst = params.dst;
12233 			}
12234 			
12235 			this.rd = this.newRd(this);
12236 			
12237 			// add the time zone offset to the rd to convert to UTC
12238 			if (!this.tz) {
12239 				this.tz = new TimeZone({id: this.timezone});
12240 			}
12241 			// getOffsetMillis requires that this.year, this.rd, and this.dst 
12242 			// are set in order to figure out which time zone rules apply and 
12243 			// what the offset is at that point in the year
12244 			this.offset = this.tz._getOffsetMillisWallTime(this) / 86400000;
12245 			if (this.offset !== 0) {
12246 				this.rd = this.newRd({
12247 					rd: this.rd.getRataDie() - this.offset
12248 				});
12249 			}
12250 		}
12251 	}
12252 	
12253 	if (!this.rd) {
12254 		this.rd = this.newRd(params);
12255 		this._calcDateComponents();
12256 	}
12257 };
12258 
12259 JulianDate.prototype = new IDate({noinstance: true});
12260 JulianDate.prototype.parent = IDate;
12261 JulianDate.prototype.constructor = JulianDate;
12262 
12263 /**
12264  * Return a new RD for this date type using the given params.
12265  * @protected
12266  * @param {Object=} params the parameters used to create this rata die instance
12267  * @returns {RataDie} the new RD instance for the given params
12268  */
12269 JulianDate.prototype.newRd = function (params) {
12270 	return new JulianRataDie(params);
12271 };
12272 
12273 /**
12274  * Return the year for the given RD
12275  * @protected
12276  * @param {number} rd RD to calculate from 
12277  * @returns {number} the year for the RD
12278  */
12279 JulianDate.prototype._calcYear = function(rd) {
12280 	var year = Math.floor((4*(Math.floor(rd)-1) + 1464)/1461);
12281 	
12282 	return (year <= 0) ? year - 1 : year;
12283 };
12284 
12285 /**
12286  * Calculate date components for the given RD date.
12287  * @protected
12288  */
12289 JulianDate.prototype._calcDateComponents = function () {
12290 	var remainder,
12291 		cumulative,
12292 		rd = this.rd.getRataDie();
12293 	
12294 	this.year = this._calcYear(rd);
12295 
12296 	if (typeof(this.offset) === "undefined") {
12297 		this.year = this._calcYear(rd);
12298 		
12299 		// now offset the RD by the time zone, then recalculate in case we were 
12300 		// near the year boundary
12301 		if (!this.tz) {
12302 			this.tz = new TimeZone({id: this.timezone});
12303 		}
12304 		this.offset = this.tz.getOffsetMillis(this) / 86400000;
12305 	}
12306 
12307 	if (this.offset !== 0) {
12308 		rd += this.offset;
12309 		this.year = this._calcYear(rd);
12310 	}
12311 	
12312 	var jan1 = this.newRd({
12313 		year: this.year,
12314 		month: 1,
12315 		day: 1,
12316 		hour: 0,
12317 		minute: 0,
12318 		second: 0,
12319 		millisecond: 0
12320 	});
12321 	remainder = rd + 1 - jan1.getRataDie();
12322 	
12323 	cumulative = this.cal.isLeapYear(this.year) ? 
12324 		JulianCal.cumMonthLengthsLeap : 
12325 		JulianCal.cumMonthLengths; 
12326 	
12327 	this.month = SearchUtils.bsearch(Math.floor(remainder), cumulative);
12328 	remainder = remainder - cumulative[this.month-1];
12329 	
12330 	this.day = Math.floor(remainder);
12331 	remainder -= this.day;
12332 	// now convert to milliseconds for the rest of the calculation
12333 	remainder = Math.round(remainder * 86400000);
12334 	
12335 	this.hour = Math.floor(remainder/3600000);
12336 	remainder -= this.hour * 3600000;
12337 	
12338 	this.minute = Math.floor(remainder/60000);
12339 	remainder -= this.minute * 60000;
12340 	
12341 	this.second = Math.floor(remainder/1000);
12342 	remainder -= this.second * 1000;
12343 	
12344 	this.millisecond = remainder;
12345 };
12346 
12347 /**
12348  * Return the day of the week of this date. The day of the week is encoded
12349  * as number from 0 to 6, with 0=Sunday, 1=Monday, etc., until 6=Saturday.
12350  * 
12351  * @return {number} the day of the week
12352  */
12353 JulianDate.prototype.getDayOfWeek = function() {
12354 	var rd = Math.floor(this.rd.getRataDie() + (this.offset || 0));
12355 	return MathUtils.mod(rd-2, 7);
12356 };
12357 
12358 /**
12359  * Return the name of the calendar that governs this date.
12360  * 
12361  * @return {string} a string giving the name of the calendar
12362  */
12363 JulianDate.prototype.getCalendar = function() {
12364 	return "julian";
12365 };
12366 
12367 //register with the factory method
12368 IDate._constructors["julian"] = JulianDate;
12369 
12370 
12371 /*< ThaiSolarCal.js */
12372 /*
12373  * thaisolar.js - Represent a Thai solar calendar object.
12374  *
12375  * Copyright © 2013-2015, JEDLSoft
12376  *
12377  * Licensed under the Apache License, Version 2.0 (the "License");
12378  * you may not use this file except in compliance with the License.
12379  * You may obtain a copy of the License at
12380  *
12381  *     http://www.apache.org/licenses/LICENSE-2.0
12382  *
12383  * Unless required by applicable law or agreed to in writing, software
12384  * distributed under the License is distributed on an "AS IS" BASIS,
12385  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12386  *
12387  * See the License for the specific language governing permissions and
12388  * limitations under the License.
12389  */
12390 
12391 
12392 /* !depends ilib.js Calendar.js GregorianCal.js MathUtils.js */
12393 
12394 
12395 /**
12396  * @class
12397  * Construct a new Thai solar calendar object. This class encodes information about
12398  * a Thai solar calendar.<p>
12399  *
12400  *
12401  * @constructor
12402  * @extends Calendar
12403  */
12404 var ThaiSolarCal = function() {
12405 	this.type = "thaisolar";
12406 };
12407 
12408 ThaiSolarCal.prototype = new GregorianCal({noinstance: true});
12409 ThaiSolarCal.prototype.parent = GregorianCal;
12410 ThaiSolarCal.prototype.constructor = ThaiSolarCal;
12411 
12412 /**
12413  * Return true if the given year is a leap year in the Thai solar calendar.
12414  * The year parameter may be given as a number, or as a ThaiSolarDate object.
12415  * @param {number|ThaiSolarDate} year the year for which the leap year information is being sought
12416  * @return {boolean} true if the given year is a leap year
12417  */
12418 ThaiSolarCal.prototype.isLeapYear = function(year) {
12419 	var y = (typeof(year) === 'number' ? year : year.getYears());
12420 	y -= 543;
12421 	var centuries = MathUtils.mod(y, 400);
12422 	return (MathUtils.mod(y, 4) === 0 && centuries !== 100 && centuries !== 200 && centuries !== 300);
12423 };
12424 
12425 /**
12426  * Return a date instance for this calendar type using the given
12427  * options.
12428  * @param {Object} options options controlling the construction of
12429  * the date instance
12430  * @return {IDate} a date appropriate for this calendar type
12431  * @deprecated Since 11.0.5. Use DateFactory({calendar: cal.getType(), ...}) instead
12432  */
12433 ThaiSolarCal.prototype.newDateInstance = function (options) {
12434 		return new ThaiSolarDate(options);
12435 };
12436 
12437 /* register this calendar for the factory method */
12438 Calendar._constructors["thaisolar"] = ThaiSolarCal;
12439 
12440 
12441 /*< ThaiSolarDate.js */
12442 /*
12443  * ThaiSolarDate.js - Represent a date in the ThaiSolar calendar
12444  * 
12445  * Copyright © 2013-2015, JEDLSoft
12446  *
12447  * Licensed under the Apache License, Version 2.0 (the "License");
12448  * you may not use this file except in compliance with the License.
12449  * You may obtain a copy of the License at
12450  *
12451  *     http://www.apache.org/licenses/LICENSE-2.0
12452  *
12453  * Unless required by applicable law or agreed to in writing, software
12454  * distributed under the License is distributed on an "AS IS" BASIS,
12455  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12456  *
12457  * See the License for the specific language governing permissions and
12458  * limitations under the License.
12459  */
12460 
12461 /* !depends 
12462 ilib.js
12463 IDate.js 
12464 JSUtils.js
12465 GregorianDate.js
12466 ThaiSolarCal.js
12467 */
12468 
12469 
12470 
12471 
12472 /**
12473  * @class
12474  * Construct a new Thai solar date object. The constructor parameters can 
12475  * contain any of the following properties:
12476  * 
12477  * <ul>
12478  * <li><i>unixtime<i> - sets the time of this instance according to the given 
12479  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970.
12480  * 
12481  * <li><i>julianday</i> - sets the time of this instance according to the given
12482  * Julian Day instance or the Julian Day given as a float
12483  * 
12484  * <li><i>year</i> - any integer, including 0
12485  * 
12486  * <li><i>month</i> - 1 to 12, where 1 means January, 2 means February, etc.
12487  * 
12488  * <li><i>day</i> - 1 to 31
12489  * 
12490  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
12491  * is always done with an unambiguous 24 hour representation
12492  * 
12493  * <li><i>minute</i> - 0 to 59
12494  * 
12495  * <li><i>second</i> - 0 to 59
12496  * 
12497  * <li><i>millisecond</i> - 0 to 999
12498  * 
12499  * <li><i>timezone</i> - the TimeZone instance or time zone name as a string 
12500  * of this Thai solar date. The date/time is kept in the local time. The time zone
12501  * is used later if this date is formatted according to a different time zone and
12502  * the difference has to be calculated, or when the date format has a time zone
12503  * component in it.
12504  * 
12505  * <li><i>locale</i> - locale for this Thai solar date. If the time zone is not 
12506  * given, it can be inferred from this locale. For locales that span multiple
12507  * time zones, the one with the largest population is chosen as the one that 
12508  * represents the locale. 
12509  * </ul>
12510  *
12511  * If the constructor is called with another Thai solar date instance instead of
12512  * a parameter block, the other instance acts as a parameter block and its
12513  * settings are copied into the current instance.<p>
12514  * 
12515  * If the constructor is called with no arguments at all or if none of the 
12516  * properties listed above 
12517  * from <i>unixtime</i> through <i>millisecond</i> are present, then the date 
12518  * components are 
12519  * filled in with the current date at the time of instantiation. Note that if
12520  * you do not give the time zone when defaulting to the current time and the 
12521  * time zone for all of ilib was not set with <i>ilib.setTimeZone()</i>, then the
12522  * time zone will default to UTC ("Universal Time, Coordinated" or "Greenwich 
12523  * Mean Time").<p>
12524  * 
12525  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
12526  * specified in the params, it is assumed that they have the smallest possible
12527  * value in the range for the property (zero or one).<p>
12528  * 
12529  * 
12530  * @constructor
12531  * @extends GregorianDate
12532  * @param {Object=} params parameters that govern the settings and behaviour of this Thai solar date
12533  */
12534 var ThaiSolarDate = function(params) {
12535 	var p = params;
12536 	if (params) {
12537 		// there is 198327 days difference between the Thai solar and 
12538 		// Gregorian epochs which is equivalent to 543 years
12539 		p = {};
12540 		JSUtils.shallowCopy(params, p);
12541 		if (typeof(p.year) !== 'undefined') {
12542 			p.year -= 543;	
12543 		}
12544 		if (typeof(p.rd) !== 'undefined') {
12545 			p.rd -= 198327;
12546 		}
12547 	}
12548 	this.rd = NaN; // clear these out so that the GregorianDate constructor can set it
12549 	this.offset = undefined;
12550 	//console.log("ThaiSolarDate.constructor: date is " + JSON.stringify(this) + " parent is " + JSON.stringify(this.parent) + " and parent.parent is " + JSON.stringify(this.parent.parent));
12551 	GregorianDate.call(this, p);
12552 	this.cal = new ThaiSolarCal();
12553 	// make sure the year is set correctly
12554 	if (params && typeof(params.year) !== 'undefined') {
12555 		this.year = parseInt(params.year, 10);
12556 	}
12557 };
12558 
12559 ThaiSolarDate.prototype = new GregorianDate({noinstance: true});
12560 ThaiSolarDate.prototype.parent = GregorianDate.prototype;
12561 ThaiSolarDate.prototype.constructor = ThaiSolarDate;
12562 
12563 /**
12564  * the difference between a zero Julian day and the zero Thai Solar date.
12565  * This is some 543 years before the start of the Gregorian epoch. 
12566  * @private
12567  * @type number
12568  */
12569 ThaiSolarDate.epoch = 1523097.5;
12570 
12571 /**
12572  * Calculate the date components for the current time zone
12573  * @protected
12574  */
12575 ThaiSolarDate.prototype._calcDateComponents = function () {
12576 	// there is 198327 days difference between the Thai solar and 
12577 	// Gregorian epochs which is equivalent to 543 years
12578 	// console.log("ThaiSolarDate._calcDateComponents: date is " + JSON.stringify(this) + " parent is " + JSON.stringify(this.parent) + " and parent.parent is " + JSON.stringify(this.parent.parent));
12579 	this.parent._calcDateComponents.call(this);
12580 	this.year += 543;
12581 };
12582 
12583 /**
12584  * Return the Rata Die (fixed day) number of this date.
12585  * 
12586  * @protected
12587  * @return {number} the rd date as a number
12588  */
12589 ThaiSolarDate.prototype.getRataDie = function() {
12590 	// there is 198327 days difference between the Thai solar and 
12591 	// Gregorian epochs which is equivalent to 543 years
12592 	return this.rd.getRataDie() + 198327;
12593 };
12594 
12595 /**
12596  * Return a new Gregorian date instance that represents the first instance of the 
12597  * given day of the week before the current date. The day of the week is encoded
12598  * as a number where 0 = Sunday, 1 = Monday, etc.
12599  * 
12600  * @param {number} dow the day of the week before the current date that is being sought
12601  * @return {IDate} the date being sought
12602  */
12603 ThaiSolarDate.prototype.before = function (dow) {
12604 	return new ThaiSolarDate({
12605 		rd: this.rd.before(dow, this.offset) + 198327,
12606 		timezone: this.timezone
12607 	});
12608 };
12609 
12610 /**
12611  * Return a new Gregorian date instance that represents the first instance of the 
12612  * given day of the week after the current date. The day of the week is encoded
12613  * as a number where 0 = Sunday, 1 = Monday, etc.
12614  * 
12615  * @param {number} dow the day of the week after the current date that is being sought
12616  * @return {IDate} the date being sought
12617  */
12618 ThaiSolarDate.prototype.after = function (dow) {
12619 	return new ThaiSolarDate({
12620 		rd: this.rd.after(dow, this.offset) + 198327,
12621 		timezone: this.timezone
12622 	});
12623 };
12624 
12625 /**
12626  * Return a new Gregorian date instance that represents the first instance of the 
12627  * given day of the week on or before the current date. The day of the week is encoded
12628  * as a number where 0 = Sunday, 1 = Monday, etc.
12629  * 
12630  * @param {number} dow the day of the week on or before the current date that is being sought
12631  * @return {IDate} the date being sought
12632  */
12633 ThaiSolarDate.prototype.onOrBefore = function (dow) {
12634 	return new ThaiSolarDate({
12635 		rd: this.rd.onOrBefore(dow, this.offset) + 198327,
12636 		timezone: this.timezone
12637 	});
12638 };
12639 
12640 /**
12641  * Return a new Gregorian date instance that represents the first instance of the 
12642  * given day of the week on or after the current date. The day of the week is encoded
12643  * as a number where 0 = Sunday, 1 = Monday, etc.
12644  * 
12645  * @param {number} dow the day of the week on or after the current date that is being sought
12646  * @return {IDate} the date being sought
12647  */
12648 ThaiSolarDate.prototype.onOrAfter = function (dow) {
12649 	return new ThaiSolarDate({
12650 		rd: this.rd.onOrAfter(dow, this.offset) + 198327,
12651 		timezone: this.timezone
12652 	});
12653 };
12654 
12655 /**
12656  * Return the name of the calendar that governs this date.
12657  * 
12658  * @return {string} a string giving the name of the calendar
12659  */
12660 ThaiSolarDate.prototype.getCalendar = function() {
12661 	return "thaisolar";
12662 };
12663 
12664 //register with the factory method
12665 IDate._constructors["thaisolar"] = ThaiSolarDate;
12666 
12667 
12668 
12669 /*< Astro.js */
12670 /*
12671  * astro.js - Static functions to support astronomical calculations
12672  * 
12673  * Copyright © 2014-2015, JEDLSoft
12674  *
12675  * Licensed under the Apache License, Version 2.0 (the "License");
12676  * you may not use this file except in compliance with the License.
12677  * You may obtain a copy of the License at
12678  *
12679  *     http://www.apache.org/licenses/LICENSE-2.0
12680  *
12681  * Unless required by applicable law or agreed to in writing, software
12682  * distributed under the License is distributed on an "AS IS" BASIS,
12683  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12684  *
12685  * See the License for the specific language governing permissions and
12686  * limitations under the License.
12687  */
12688 
12689 /* !depends
12690 ilib.js
12691 IDate.js
12692 Utils.js
12693 MathUtils.js
12694 SearchUtils.js
12695 GregorianDate.js
12696 GregRataDie.js
12697 */
12698 
12699 // !data astro
12700 
12701 /*
12702  * These routines were derived from a public domain set of JavaScript 
12703  * functions for positional astronomy by John Walker of Fourmilab, 
12704  * September 1999.
12705  */
12706 
12707 
12708 
12709 var Astro = {};
12710 
12711 /**
12712  * Load in all the data needed for astrological calculations.
12713  * 
12714  * @private
12715  * @param {boolean} sync
12716  * @param {*} loadParams
12717  * @param {function(*)|undefined} callback
12718  */
12719 Astro.initAstro = function(sync, loadParams, callback) {
12720 	if (!ilib.data.astro) {
12721 		Utils.loadData({
12722 			name: "astro.json", // countries in their own language 
12723 			locale: "-", // only need to load the root file 
12724 			nonLocale: true,
12725 			sync: sync, 
12726 			loadParams: loadParams, 
12727 			callback: ilib.bind(this, function(astroData) {
12728 				/** 
12729 				 * @type {{
12730 				 *  	_EquinoxpTerms:Array.<number>, 
12731 				 *  	_JDE0tab1000:Array.<number>, 
12732 				 *  	_JDE0tab2000:Array.<number>, 
12733 				 *  	_deltaTtab:Array.<number>,
12734 				 *  	_oterms:Array.<number>,
12735 				 *  	_nutArgMult:Array.<number>, 
12736 				 *  	_nutArgCoeff:Array.<number>, 
12737 				 *  	_nutCoeffA:Array.<number>,
12738 				 *  	_nutCoeffB:Array.<number>,
12739 				 *  	_coeff19th:Array.<number>,
12740 				 *  	_coeff18th:Array.<number>,
12741 				 *  	_solarLongCoeff:Array.<number>, 
12742 				 *  	_solarLongMultipliers:Array.<number>, 
12743 				 *  	_solarLongAddends:Array.<number>, 
12744 				 *  	_meanMoonCoeff:Array.<number>,
12745 				 *  	_elongationCoeff:Array.<number>,
12746 				 *  	_solarAnomalyCoeff:Array.<number>,
12747 				 *  	_lunarAnomalyCoeff:Array.<number>,
12748 				 *  	_moonFromNodeCoeff:Array.<number>,
12749 				 *  	_eCoeff:Array.<number>,
12750 				 *  	_lunarElongationLongCoeff:Array.<number>,
12751 				 *  	_solarAnomalyLongCoeff:Array.<number>,
12752 				 *  	_lunarAnomalyLongCoeff:Array.<number>,
12753 				 *  	_moonFromNodeLongCoeff:Array.<number>,
12754 				 *  	_sineCoeff:Array.<number>,
12755 				 *  	_nmApproxCoeff:Array.<number>,
12756 				 *  	_nmCapECoeff:Array.<number>,
12757 				 *  	_nmSolarAnomalyCoeff:Array.<number>,
12758 				 *  	_nmLunarAnomalyCoeff:Array.<number>,
12759 				 *  	_nmMoonArgumentCoeff:Array.<number>,
12760 				 *  	_nmCapOmegaCoeff:Array.<number>,
12761 				 *  	_nmEFactor:Array.<number>,
12762 				 *  	_nmSolarCoeff:Array.<number>,
12763 				 *  	_nmLunarCoeff:Array.<number>,
12764 				 *  	_nmMoonCoeff:Array.<number>,
12765 				 *  	_nmSineCoeff:Array.<number>,
12766 				 *  	_nmAddConst:Array.<number>,
12767 				 *  	_nmAddCoeff:Array.<number>,
12768 				 *  	_nmAddFactor:Array.<number>,
12769 				 *  	_nmExtra:Array.<number>
12770 				 *  }}
12771 				 */ 	
12772 			 	ilib.data.astro = astroData;
12773 				if (callback && typeof(callback) === 'function') {
12774 					callback(astroData);
12775 				}
12776 			})
12777 		});
12778 	} else {
12779 		if (callback && typeof(callback) === 'function') {
12780 			callback(ilib.data.astro);
12781 		}
12782 	}
12783 };
12784 
12785 /**
12786  * Convert degrees to radians.
12787  * 
12788  * @static
12789  * @protected
12790  * @param {number} d angle in degrees
12791  * @return {number} angle in radians 
12792  */
12793 Astro._dtr = function(d) {
12794 	return (d * Math.PI) / 180.0;
12795 };
12796 
12797 /**
12798  * Convert radians to degrees.
12799  * 
12800  * @static
12801  * @protected
12802  * @param {number} r angle in radians
12803  * @return {number} angle in degrees 
12804  */
12805 Astro._rtd = function(r) {
12806 	return (r * 180.0) / Math.PI;
12807 };
12808 
12809 /**
12810  * Return the cosine of an angle given in degrees.
12811  * @static
12812  * @protected
12813  * @param {number} d angle in degrees
12814  * @return {number} cosine of the angle.
12815  */  
12816 Astro._dcos = function(d) {
12817 	return Math.cos(Astro._dtr(d));
12818 };
12819 
12820 /**
12821  * Return the sine of an angle given in degrees.
12822  * @static
12823  * @protected
12824  * @param {number} d angle in degrees
12825  * @return {number} sine of the angle.
12826  */  
12827 Astro._dsin = function(d) {
12828 	return Math.sin(Astro._dtr(d));
12829 };
12830 
12831 /**
12832  * Return the tan of an angle given in degrees.
12833  * @static
12834  * @protected
12835  * @param {number} d angle in degrees
12836  * @return {number} tan of the angle.
12837  */  
12838 Astro._dtan = function(d) {
12839 	return Math.tan(Astro._dtr(d));
12840 };
12841 
12842 /**
12843  * Range reduce angle in degrees.
12844  * 
12845  * @static
12846  * @param {number} a angle to reduce
12847  * @return {number} the reduced angle  
12848  */
12849 Astro._fixangle = function(a) {
12850 	return a - 360.0 * (Math.floor(a / 360.0));
12851 };
12852 
12853 /**
12854  * Range reduce angle in radians.
12855  * 
12856  * @static
12857  * @protected
12858  * @param {number} a angle to reduce
12859  * @return {number} the reduced angle  
12860  */
12861 Astro._fixangr = function(a) {
12862 	return a - (2 * Math.PI) * (Math.floor(a / (2 * Math.PI)));
12863 };
12864 
12865 /**
12866  * Determine the Julian Ephemeris Day of an equinox or solstice.  The "which" 
12867  * argument selects the item to be computed:
12868  * 
12869  * <ul>
12870  * <li>0   March equinox
12871  * <li>1   June solstice
12872  * <li>2   September equinox
12873  * <li>3   December solstice
12874  * </ul>
12875  * 
12876  * @static
12877  * @protected
12878  * @param {number} year Gregorian year to calculate for
12879  * @param {number} which Which equinox or solstice to calculate
12880  */
12881 Astro._equinox = function(year, which) {
12882 	var deltaL, i, j, JDE0, JDE, JDE0tab, S, T, W, Y;
12883 
12884 	/*  Initialize terms for mean equinox and solstices.  We
12885 	    have two sets: one for years prior to 1000 and a second
12886 	    for subsequent years.  */
12887 
12888 	if (year < 1000) {
12889 		JDE0tab = ilib.data.astro._JDE0tab1000;
12890 		Y = year / 1000;
12891 	} else {
12892 		JDE0tab = ilib.data.astro._JDE0tab2000;
12893 		Y = (year - 2000) / 1000;
12894 	}
12895 
12896 	JDE0 = JDE0tab[which][0] + (JDE0tab[which][1] * Y)
12897 			+ (JDE0tab[which][2] * Y * Y) + (JDE0tab[which][3] * Y * Y * Y)
12898 			+ (JDE0tab[which][4] * Y * Y * Y * Y);
12899 
12900 	//document.debug.log.value += "JDE0 = " + JDE0 + "\n";
12901 
12902 	T = (JDE0 - 2451545.0) / 36525;
12903 	//document.debug.log.value += "T = " + T + "\n";
12904 	W = (35999.373 * T) - 2.47;
12905 	//document.debug.log.value += "W = " + W + "\n";
12906 	deltaL = 1 + (0.0334 * Astro._dcos(W)) + (0.0007 * Astro._dcos(2 * W));
12907 	//document.debug.log.value += "deltaL = " + deltaL + "\n";
12908 
12909 	//  Sum the periodic terms for time T
12910 
12911 	S = 0;
12912 	j = 0;
12913 	for (i = 0; i < 24; i++) {
12914 		S += ilib.data.astro._EquinoxpTerms[j]
12915 				* Astro._dcos(ilib.data.astro._EquinoxpTerms[j + 1] + (ilib.data.astro._EquinoxpTerms[j + 2] * T));
12916 		j += 3;
12917 	}
12918 
12919 	//document.debug.log.value += "S = " + S + "\n";
12920 	//document.debug.log.value += "Corr = " + ((S * 0.00001) / deltaL) + "\n";
12921 
12922 	JDE = JDE0 + ((S * 0.00001) / deltaL);
12923 
12924 	return JDE;
12925 };
12926 
12927 /* 
12928  * The table of observed Delta T values at the beginning of
12929  * years from 1620 through 2014 as found in astro.json is taken from
12930  * http://www.staff.science.uu.nl/~gent0113/deltat/deltat.htm
12931  * and
12932  * ftp://maia.usno.navy.mil/ser7/deltat.data
12933  */
12934 
12935 /**  
12936  * Determine the difference, in seconds, between dynamical time and universal time.
12937  * 
12938  * @static
12939  * @protected
12940  * @param {number} year to calculate the difference for
12941  * @return {number} difference in seconds between dynamical time and universal time  
12942  */
12943 Astro._deltat = function (year) {
12944 	var dt, f, i, t;
12945 
12946 	if ((year >= 1620) && (year <= 2014)) {
12947 		i = Math.floor(year - 1620);
12948 		f = (year - 1620) - i; /* Fractional part of year */
12949 		dt = ilib.data.astro._deltaTtab[i] + ((ilib.data.astro._deltaTtab[i + 1] - ilib.data.astro._deltaTtab[i]) * f);
12950 	} else {
12951 		t = (year - 2000) / 100;
12952 		if (year < 948) {
12953 			dt = 2177 + (497 * t) + (44.1 * t * t);
12954 		} else {
12955 			dt = 102 + (102 * t) + (25.3 * t * t);
12956 			if ((year > 2000) && (year < 2100)) {
12957 				dt += 0.37 * (year - 2100);
12958 			}
12959 		}
12960 	}
12961 	return dt;
12962 };
12963 
12964 /**
12965  * Calculate the obliquity of the ecliptic for a given
12966  * Julian date.  This uses Laskar's tenth-degree
12967  * polynomial fit (J. Laskar, Astronomy and
12968  * Astrophysics, Vol. 157, page 68 [1986]) which is
12969  * accurate to within 0.01 arc second between AD 1000
12970  * and AD 3000, and within a few seconds of arc for
12971  * +/-10000 years around AD 2000.  If we're outside the
12972  * range in which this fit is valid (deep time) we
12973  * simply return the J2000 value of the obliquity, which
12974  * happens to be almost precisely the mean.
12975  * 
12976  * @static
12977  * @protected
12978  * @param {number} jd Julian Day to calculate the obliquity for
12979  * @return {number} the obliquity
12980  */
12981 Astro._obliqeq = function (jd) {
12982 	var eps, u, v, i;
12983 
12984  	v = u = (jd - 2451545.0) / 3652500.0;
12985 
12986  	eps = 23 + (26 / 60.0) + (21.448 / 3600.0);
12987 
12988  	if (Math.abs(u) < 1.0) {
12989  		for (i = 0; i < 10; i++) {
12990  			eps += (ilib.data.astro._oterms[i] / 3600.0) * v;
12991  			v *= u;
12992  		}
12993  	}
12994  	return eps;
12995 };
12996 
12997 /**
12998  * Return the position of the sun.  We return
12999  * intermediate values because they are useful in a
13000  * variety of other contexts.
13001  * @static
13002  * @protected
13003  * @param {number} jd find the position of sun on this Julian Day
13004  * @return {Object} the position of the sun and many intermediate
13005  * values
13006  */
13007 Astro._sunpos = function(jd) {
13008 	var ret = {}, 
13009 		T, T2, T3, Omega, epsilon, epsilon0;
13010 
13011 	T = (jd - 2451545.0) / 36525.0;
13012 	//document.debug.log.value += "Sunpos.  T = " + T + "\n";
13013 	T2 = T * T;
13014 	T3 = T * T2;
13015 	ret.meanLongitude = Astro._fixangle(280.46646 + 36000.76983 * T + 0.0003032 * T2);
13016 	//document.debug.log.value += "ret.meanLongitude = " + ret.meanLongitude + "\n";
13017 	ret.meanAnomaly = Astro._fixangle(357.52911 + (35999.05029 * T) - 0.0001537 * T2 - 0.00000048 * T3);
13018 	//document.debug.log.value += "ret.meanAnomaly = " + ret.meanAnomaly + "\n";
13019 	ret.eccentricity = 0.016708634 - 0.000042037 * T - 0.0000001267 * T2;
13020 	//document.debug.log.value += "e = " + e + "\n";
13021 	ret.equationOfCenter = ((1.914602 - 0.004817 * T - 0.000014 * T2) * Astro._dsin(ret.meanAnomaly))
13022 			+ ((0.019993 - 0.000101 * T) * Astro._dsin(2 * ret.meanAnomaly))
13023 			+ (0.000289 * Astro._dsin(3 * ret.meanAnomaly));
13024 	//document.debug.log.value += "ret.equationOfCenter = " + ret.equationOfCenter + "\n";
13025 	ret.sunLongitude = ret.meanLongitude + ret.equationOfCenter;
13026 	//document.debug.log.value += "ret.sunLongitude = " + ret.sunLongitude + "\n";
13027 	//ret.sunAnomaly = ret.meanAnomaly + ret.equationOfCenter;
13028 	//document.debug.log.value += "ret.sunAnomaly = " + ret.sunAnomaly + "\n";
13029 	// ret.sunRadius = (1.000001018 * (1 - (ret.eccentricity * ret.eccentricity))) / (1 + (ret.eccentricity * Astro._dcos(ret.sunAnomaly)));
13030 	//document.debug.log.value += "ret.sunRadius = " + ret.sunRadius + "\n";
13031 	Omega = 125.04 - (1934.136 * T);
13032 	//document.debug.log.value += "Omega = " + Omega + "\n";
13033 	ret.apparentLong = ret.sunLongitude + (-0.00569) + (-0.00478 * Astro._dsin(Omega));
13034 	//document.debug.log.value += "ret.apparentLong = " + ret.apparentLong + "\n";
13035 	epsilon0 = Astro._obliqeq(jd);
13036 	//document.debug.log.value += "epsilon0 = " + epsilon0 + "\n";
13037 	epsilon = epsilon0 + (0.00256 * Astro._dcos(Omega));
13038 	//document.debug.log.value += "epsilon = " + epsilon + "\n";
13039 	//ret.rightAscension = Astro._fixangle(Astro._rtd(Math.atan2(Astro._dcos(epsilon0) * Astro._dsin(ret.sunLongitude), Astro._dcos(ret.sunLongitude))));
13040 	//document.debug.log.value += "ret.rightAscension = " + ret.rightAscension + "\n";
13041 	// ret.declination = Astro._rtd(Math.asin(Astro._dsin(epsilon0) * Astro._dsin(ret.sunLongitude)));
13042 	////document.debug.log.value += "ret.declination = " + ret.declination + "\n";
13043 	ret.inclination = Astro._fixangle(23.4392911 - 0.013004167 * T - 0.00000016389 * T2 + 0.0000005036 * T3);
13044 	ret.apparentRightAscension = Astro._fixangle(Astro._rtd(Math.atan2(Astro._dcos(epsilon) * Astro._dsin(ret.apparentLong), Astro._dcos(ret.apparentLong))));
13045 	//document.debug.log.value += "ret.apparentRightAscension = " + ret.apparentRightAscension + "\n";
13046 	//ret.apparentDeclination = Astro._rtd(Math.asin(Astro._dsin(epsilon) * Astro._dsin(ret.apparentLong)));
13047 	//document.debug.log.value += "ret.apparentDecliation = " + ret.apparentDecliation + "\n";
13048 
13049 	// Angular quantities are expressed in decimal degrees
13050 	return ret;
13051 };
13052 
13053 /**
13054  * Calculate the nutation in longitude, deltaPsi, and obliquity, 
13055  * deltaEpsilon for a given Julian date jd. Results are returned as an object
13056  * giving deltaPsi and deltaEpsilon in degrees.
13057  * 
13058  * @static
13059  * @protected
13060  * @param {number} jd calculate the nutation of this Julian Day
13061  * @return {Object} the deltaPsi and deltaEpsilon of the nutation
13062  */
13063 Astro._nutation = function(jd) {
13064 	var i, j, 
13065 		t = (jd - 2451545.0) / 36525.0, 
13066 		t2, t3, to10, 
13067 		ta = [], 
13068 		dp = 0, 
13069 		de = 0, 
13070 		ang,
13071 		ret = {};
13072 
13073 	t3 = t * (t2 = t * t);
13074 
13075 	/*
13076 	 * Calculate angles. The correspondence between the elements of our array
13077 	 * and the terms cited in Meeus are:
13078 	 * 
13079 	 * ta[0] = D ta[0] = M ta[2] = M' ta[3] = F ta[4] = \Omega
13080 	 * 
13081 	 */
13082 
13083 	ta[0] = Astro._dtr(297.850363 + 445267.11148 * t - 0.0019142 * t2 + t3 / 189474.0);
13084 	ta[1] = Astro._dtr(357.52772 + 35999.05034 * t - 0.0001603 * t2 - t3 / 300000.0);
13085 	ta[2] = Astro._dtr(134.96298 + 477198.867398 * t + 0.0086972 * t2 + t3 / 56250.0);
13086 	ta[3] = Astro._dtr(93.27191 + 483202.017538 * t - 0.0036825 * t2 + t3 / 327270);
13087 	ta[4] = Astro._dtr(125.04452 - 1934.136261 * t + 0.0020708 * t2 + t3 / 450000.0);
13088 
13089 	/*
13090 	 * Range reduce the angles in case the sine and cosine functions don't do it
13091 	 * as accurately or quickly.
13092 	 */
13093 
13094 	for (i = 0; i < 5; i++) {
13095 		ta[i] = Astro._fixangr(ta[i]);
13096 	}
13097 
13098 	to10 = t / 10.0;
13099 	for (i = 0; i < 63; i++) {
13100 		ang = 0;
13101 		for (j = 0; j < 5; j++) {
13102 			if (ilib.data.astro._nutArgMult[(i * 5) + j] != 0) {
13103 				ang += ilib.data.astro._nutArgMult[(i * 5) + j] * ta[j];
13104 			}
13105 		}
13106 		dp += (ilib.data.astro._nutArgCoeff[(i * 4) + 0] + ilib.data.astro._nutArgCoeff[(i * 4) + 1] * to10) * Math.sin(ang);
13107 		de += (ilib.data.astro._nutArgCoeff[(i * 4) + 2] + ilib.data.astro._nutArgCoeff[(i * 4) + 3] * to10) * Math.cos(ang);
13108 	}
13109 
13110 	/*
13111 	 * Return the result, converting from ten thousandths of arc seconds to
13112 	 * radians in the process.
13113 	 */
13114 
13115 	ret.deltaPsi = dp / (3600.0 * 10000.0);
13116 	ret.deltaEpsilon = de / (3600.0 * 10000.0);
13117 
13118 	return ret;
13119 };
13120 
13121 /**
13122  * Returns the equation of time as a fraction of a day.
13123  * 
13124  * @static
13125  * @protected
13126  * @param {number} jd the Julian Day of the day to calculate for
13127  * @return {number} the equation of time for the given day  
13128  */
13129 Astro._equationOfTime = function(jd) {
13130 	var alpha, deltaPsi, E, epsilon, L0, tau, pos;
13131 
13132 	// 2451545.0 is the Julian day of J2000 epoch
13133 	// 365250.0 is the number of days in a Julian millenium
13134 	tau = (jd - 2451545.0) / 365250.0;
13135 	//console.log("equationOfTime.  tau = " + tau);
13136 	L0 = 280.4664567 + (360007.6982779 * tau) + (0.03032028 * tau * tau)
13137 			+ ((tau * tau * tau) / 49931)
13138 			+ (-((tau * tau * tau * tau) / 15300))
13139 			+ (-((tau * tau * tau * tau * tau) / 2000000));
13140 	//console.log("L0 = " + L0);
13141 	L0 = Astro._fixangle(L0);
13142 	//console.log("L0 = " + L0);
13143 	pos = Astro._sunpos(jd);
13144 	alpha = pos.apparentRightAscension;
13145 	//console.log("alpha = " + alpha);
13146 	var nut = Astro._nutation(jd);
13147 	deltaPsi = nut.deltaPsi;
13148 	//console.log("deltaPsi = " + deltaPsi);
13149 	epsilon = Astro._obliqeq(jd) + nut.deltaEpsilon;
13150 	//console.log("epsilon = " + epsilon);
13151 	//console.log("L0 - 0.0057183 = " + (L0 - 0.0057183));
13152 	//console.log("L0 - 0.0057183 - alpha = " + (L0 - 0.0057183 - alpha));
13153 	//console.log("deltaPsi * cos(epsilon) = " + deltaPsi * Astro._dcos(epsilon));
13154 	
13155 	E = L0 - 0.0057183 - alpha + deltaPsi * Astro._dcos(epsilon);
13156 	// if alpha and L0 are in different quadrants, then renormalize
13157 	// so that the difference between them is in the right range
13158 	if (E > 180) {
13159 		E -= 360;
13160 	}
13161 	//console.log("E = " + E);
13162 	// E = E - 20.0 * (Math.floor(E / 20.0));
13163 	E = E * 4;
13164 	//console.log("Efixed = " + E);
13165 	E = E / (24 * 60);
13166 	//console.log("Eday = " + E);
13167 
13168 	return E;
13169 };
13170 
13171 /**
13172  * @private
13173  * @static
13174  */
13175 Astro._poly = function(x, coefficients) {
13176 	var result = coefficients[0];
13177 	var xpow = x;
13178 	for (var i = 1; i < coefficients.length; i++) {
13179 		result += coefficients[i] * xpow;
13180 		xpow *= x;
13181 	}
13182 	return result;
13183 };
13184 
13185 /**
13186  * Calculate the UTC RD from the local RD given "zone" number of minutes
13187  * worth of offset.
13188  * 
13189  * @static
13190  * @protected
13191  * @param {number} local RD of the locale time, given in any calendar
13192  * @param {number} zone number of minutes of offset from UTC for the time zone 
13193  * @return {number} the UTC equivalent of the local RD
13194  */
13195 Astro._universalFromLocal = function(local, zone) {
13196 	return local - zone / 1440;
13197 };
13198 
13199 /**
13200  * Calculate the local RD from the UTC RD given "zone" number of minutes
13201  * worth of offset.
13202  * 
13203  * @static
13204  * @protected
13205  * @param {number} local RD of the locale time, given in any calendar
13206  * @param {number} zone number of minutes of offset from UTC for the time zone 
13207  * @return {number} the UTC equivalent of the local RD
13208  */
13209 Astro._localFromUniversal = function(local, zone) {
13210 	return local + zone / 1440;
13211 };
13212 
13213 /**
13214  * @private
13215  * @static
13216  * @param {number} c julian centuries of the date to calculate
13217  * @return {number} the aberration
13218  */
13219 Astro._aberration = function(c) {
13220 	return 9.74e-05 * Astro._dcos(177.63 + 35999.01847999999 * c) - 0.005575;
13221 };
13222 
13223 /**
13224  * @private
13225  *
13226 ilib.data.astro._nutCoeffA = [124.90, -1934.134, 0.002063];
13227 ilib.data.astro._nutCoeffB q= [201.11, 72001.5377, 0.00057];
13228 */
13229 
13230 /**
13231  * @private
13232  * @static
13233  * @param {number} c julian centuries of the date to calculate
13234  * @return {number} the nutation for the given julian century in radians
13235  */
13236 Astro._nutation2 = function(c) {
13237 	var a = Astro._poly(c, ilib.data.astro._nutCoeffA);
13238 	var b = Astro._poly(c, ilib.data.astro._nutCoeffB);
13239 	// return -0.0000834 * Astro._dsin(a) - 0.0000064 * Astro._dsin(b);
13240 	return -0.004778 * Astro._dsin(a) - 0.0003667 * Astro._dsin(b);
13241 };
13242 
13243 /**
13244  * @static
13245  * @private
13246  */
13247 Astro._ephemerisCorrection = function(jd) {
13248 	var year = GregorianDate._calcYear(jd - 1721424.5);
13249 	
13250 	if (1988 <= year && year <= 2019) {
13251 		return (year - 1933) / 86400;
13252 	}
13253 	
13254 	if (1800 <= year && year <= 1987) {
13255 		var jul1 = new GregRataDie({
13256 			year: year,
13257 			month: 7,
13258 			day: 1,
13259 			hour: 0,
13260 			minute: 0,
13261 			second: 0
13262 		});
13263 		// 693596 is the rd of Jan 1, 1900
13264 		var theta = (jul1.getRataDie() - 693596) / 36525;
13265 		return Astro._poly(theta, (1900 <= year) ? ilib.data.astro._coeff19th : ilib.data.astro._coeff18th);
13266 	}
13267 	
13268 	if (1620 <= year && year <= 1799) {
13269 		year -= 1600;
13270 		return (196.58333 - 4.0675 * year + 0.0219167 * year * year) / 86400;
13271 	}
13272 	
13273 	// 660724 is the rd of Jan 1, 1810
13274 	var jan1 = new GregRataDie({
13275 		year: year,
13276 		month: 1,
13277 		day: 1,
13278 		hour: 0,
13279 		minute: 0,
13280 		second: 0
13281 	});
13282 	// var x = 0.5 + (jan1.getRataDie() - 660724);
13283 	var x = 0.5 + (jan1.getRataDie() - 660724);
13284 	
13285 	return ((x * x / 41048480) - 15) / 86400;
13286 };
13287 
13288 /**
13289  * @static
13290  * @private
13291  */
13292 Astro._ephemerisFromUniversal = function(jd) {
13293 	return jd + Astro._ephemerisCorrection(jd);
13294 };
13295 
13296 /**
13297  * @static
13298  * @private
13299  */
13300 Astro._universalFromEphemeris = function(jd) {
13301 	return jd - Astro._ephemerisCorrection(jd);
13302 };
13303 
13304 /**
13305  * @static
13306  * @private
13307  */
13308 Astro._julianCenturies = function(jd) {
13309 	// 2451545.0 is the Julian day of J2000 epoch
13310 	// 730119.5 is the Gregorian RD of J2000 epoch
13311 	// 36525.0 is the number of days in a Julian century
13312 	return (Astro._ephemerisFromUniversal(jd) - 2451545.0) / 36525.0;
13313 };
13314 
13315 /**
13316  * Calculate the solar longitude
13317  * 
13318  * @static
13319  * @protected
13320  * @param {number} jd julian day of the date to calculate the longitude for 
13321  * @return {number} the solar longitude in degrees
13322  */
13323 Astro._solarLongitude = function(jd) {
13324 	var c = Astro._julianCenturies(jd),
13325 		longitude = 0,
13326 		len = ilib.data.astro._solarLongCoeff.length,
13327 		row;
13328 	
13329 	for (var i = 0; i < len; i++) {
13330 		longitude += ilib.data.astro._solarLongCoeff[i] * 
13331 			Astro._dsin(ilib.data.astro._solarLongAddends[i] + ilib.data.astro._solarLongMultipliers[i] * c);
13332 	}
13333 	longitude *= 5.729577951308232e-06;
13334 	longitude += 282.77718340000001 + 36000.769537439999 * c;
13335 	longitude += Astro._aberration(c) + Astro._nutation2(c);
13336 	return Astro._fixangle(longitude);
13337 };
13338 
13339 /**
13340  * @static
13341  * @protected
13342  * @param {number} jd
13343  * @return {number}
13344  */
13345 Astro._lunarLongitude = function (jd) {
13346 	var c = Astro._julianCenturies(jd),
13347 	    meanMoon = Astro._fixangle(Astro._poly(c, ilib.data.astro._meanMoonCoeff)),
13348 	    elongation = Astro._fixangle(Astro._poly(c, ilib.data.astro._elongationCoeff)),
13349 	    solarAnomaly = Astro._fixangle(Astro._poly(c, ilib.data.astro._solarAnomalyCoeff)),
13350 	    lunarAnomaly = Astro._fixangle(Astro._poly(c, ilib.data.astro._lunarAnomalyCoeff)),
13351 	    moonNode = Astro._fixangle(Astro._poly(c, ilib.data.astro._moonFromNodeCoeff)),
13352 	    e = Astro._poly(c, ilib.data.astro._eCoeff);
13353 	
13354 	var sum = 0;
13355 	for (var i = 0; i < ilib.data.astro._lunarElongationLongCoeff.length; i++) {
13356 		var x = ilib.data.astro._solarAnomalyLongCoeff[i];
13357 
13358 		sum += ilib.data.astro._sineCoeff[i] * Math.pow(e, Math.abs(x)) * 
13359 			Astro._dsin(ilib.data.astro._lunarElongationLongCoeff[i] * elongation + x * solarAnomaly + 
13360 				ilib.data.astro._lunarAnomalyLongCoeff[i] * lunarAnomaly + 
13361 				ilib.data.astro._moonFromNodeLongCoeff[i] * moonNode);
13362 	}
13363 	var longitude = sum / 1000000;
13364 	var venus = 3958.0 / 1000000 * Astro._dsin(119.75 + c * 131.84899999999999);
13365 	var jupiter = 318.0 / 1000000 * Astro._dsin(53.090000000000003 + c * 479264.28999999998);
13366 	var flatEarth = 1962.0 / 1000000 * Astro._dsin(meanMoon - moonNode);
13367 	
13368 	return Astro._fixangle(meanMoon + longitude + venus + jupiter + flatEarth + Astro._nutation2(c));
13369 };
13370 
13371 /**
13372  * @static
13373  * @protected
13374  * @param {number} n
13375  * @return {number} julian day of the n'th new moon
13376  */
13377 Astro._newMoonTime = function(n) {
13378 	var k = n - 24724;
13379 	var c = k / 1236.8499999999999;
13380 	var approx = Astro._poly(c, ilib.data.astro._nmApproxCoeff);
13381 	var capE = Astro._poly(c, ilib.data.astro._nmCapECoeff);
13382 	var solarAnomaly = Astro._poly(c, ilib.data.astro._nmSolarAnomalyCoeff);
13383 	var lunarAnomaly = Astro._poly(c, ilib.data.astro._nmLunarAnomalyCoeff);
13384 	var moonArgument = Astro._poly(c, ilib.data.astro._nmMoonArgumentCoeff);
13385 	var capOmega = Astro._poly(c, ilib.data.astro._nmCapOmegaCoeff);
13386 	var correction = -0.00017 * Astro._dsin(capOmega);
13387 	for (var i = 0; i < ilib.data.astro._nmSineCoeff.length; i++) {
13388 		correction = correction + ilib.data.astro._nmSineCoeff[i] * Math.pow(capE, ilib.data.astro._nmEFactor[i]) * 
13389 		Astro._dsin(ilib.data.astro._nmSolarCoeff[i] * solarAnomaly + 
13390 				ilib.data.astro._nmLunarCoeff[i] * lunarAnomaly + 
13391 				ilib.data.astro._nmMoonCoeff[i] * moonArgument);
13392 	}
13393 	var additional = 0;
13394 	for (var i = 0; i < ilib.data.astro._nmAddConst.length; i++) {
13395 		additional = additional + ilib.data.astro._nmAddFactor[i] * 
13396 		Astro._dsin(ilib.data.astro._nmAddConst[i] + ilib.data.astro._nmAddCoeff[i] * k);
13397 	}
13398 	var extra = 0.000325 * Astro._dsin(Astro._poly(c, ilib.data.astro._nmExtra));
13399 	return Astro._universalFromEphemeris(approx + correction + extra + additional + RataDie.gregorianEpoch);
13400 };
13401 
13402 /**
13403  * @static
13404  * @protected
13405  * @param {number} jd
13406  * @return {number}
13407  */
13408 Astro._lunarSolarAngle = function(jd) {
13409 	var lunar = Astro._lunarLongitude(jd);
13410 	var solar = Astro._solarLongitude(jd)
13411 	return Astro._fixangle(lunar - solar);
13412 };
13413 
13414 /**
13415  * @static
13416  * @protected
13417  * @param {number} jd
13418  * @return {number}
13419  */
13420 Astro._newMoonBefore = function (jd) {
13421 	var phase = Astro._lunarSolarAngle(jd);
13422 	// 11.450086114414322 is the julian day of the 0th full moon
13423 	// 29.530588853000001 is the average length of a month
13424 	var guess = Math.round((jd - 11.450086114414322 - RataDie.gregorianEpoch) / 29.530588853000001 - phase / 360) - 1;
13425 	var current, last;
13426 	current = last = Astro._newMoonTime(guess);
13427 	while (current < jd) {
13428 		guess++;
13429 		last = current;
13430 		current = Astro._newMoonTime(guess);
13431 	}
13432 	return last;
13433 };
13434 
13435 /**
13436  * @static
13437  * @protected
13438  * @param {number} jd
13439  * @return {number}
13440  */
13441 Astro._newMoonAtOrAfter = function (jd) {
13442 	var phase = Astro._lunarSolarAngle(jd);
13443 	// 11.450086114414322 is the julian day of the 0th full moon
13444 	// 29.530588853000001 is the average length of a month
13445 	var guess = Math.round((jd - 11.450086114414322 - RataDie.gregorianEpoch) / 29.530588853000001 - phase / 360);
13446 	var current;
13447 	while ((current = Astro._newMoonTime(guess)) < jd) {
13448 		guess++;
13449 	}
13450 	return current;
13451 };
13452 
13453 /**
13454  * @static
13455  * @protected
13456  * @param {number} jd JD to calculate from
13457  * @param {number} longitude longitude to seek 
13458  * @returns {number} the JD of the next time that the solar longitude 
13459  * is a multiple of the given longitude
13460  */
13461 Astro._nextSolarLongitude = function(jd, longitude) {
13462 	var rate = 365.242189 / 360.0;
13463 	var tau = jd + rate * Astro._fixangle(longitude - Astro._solarLongitude(jd));
13464 	var start = Math.max(jd, tau - 5.0);
13465 	var end = tau + 5.0;
13466 	
13467 	return SearchUtils.bisectionSearch(0, start, end, 1e-6, function (l) {
13468 		return 180 - Astro._fixangle(Astro._solarLongitude(l) - longitude);
13469 	});
13470 };
13471 
13472 /**
13473  * Floor the julian day to midnight of the current julian day.
13474  * 
13475  * @static
13476  * @protected
13477  * @param {number} jd the julian to round
13478  * @return {number} the jd floored to the midnight of the julian day
13479  */
13480 Astro._floorToJD = function(jd) {
13481 	return Math.floor(jd - 0.5) + 0.5;
13482 };
13483 
13484 /**
13485  * Floor the julian day to midnight of the current julian day.
13486  * 
13487  * @static
13488  * @protected
13489  * @param {number} jd the julian to round
13490  * @return {number} the jd floored to the midnight of the julian day
13491  */
13492 Astro._ceilToJD = function(jd) {
13493 	return Math.ceil(jd + 0.5) - 0.5;
13494 };
13495 
13496 
13497 
13498 /*< PersRataDie.js */
13499 /*
13500  * persratadie.js - Represent a rata die date in the Persian calendar
13501  * 
13502  * Copyright © 2014-2015, JEDLSoft
13503  *
13504  * Licensed under the Apache License, Version 2.0 (the "License");
13505  * you may not use this file except in compliance with the License.
13506  * You may obtain a copy of the License at
13507  *
13508  *     http://www.apache.org/licenses/LICENSE-2.0
13509  *
13510  * Unless required by applicable law or agreed to in writing, software
13511  * distributed under the License is distributed on an "AS IS" BASIS,
13512  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13513  *
13514  * See the License for the specific language governing permissions and
13515  * limitations under the License.
13516  */
13517 
13518 /* !depends 
13519 ilib.js
13520 MathUtils.js
13521 RataDie.js
13522 Astro.js
13523 GregorianDate.js
13524 */
13525 
13526 
13527 
13528 
13529 /**
13530  * @class
13531  * Construct a new Persian RD date number object. The constructor parameters can 
13532  * contain any of the following properties:
13533  * 
13534  * <ul>
13535  * <li><i>unixtime<i> - sets the time of this instance according to the given 
13536  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970, Gregorian
13537  * 
13538  * <li><i>julianday</i> - sets the time of this instance according to the given
13539  * Julian Day instance or the Julian Day given as a float
13540  * 
13541  * <li><i>year</i> - any integer, including 0
13542  * 
13543  * <li><i>month</i> - 1 to 12, where 1 means Farvardin, 2 means Ordibehesht, etc.
13544  * 
13545  * <li><i>day</i> - 1 to 31
13546  * 
13547  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
13548  * is always done with an unambiguous 24 hour representation
13549  * 
13550  * <li><i>minute</i> - 0 to 59
13551  * 
13552  * <li><i>second</i> - 0 to 59
13553  * 
13554  * <li><i>millisecond</i> - 0 to 999
13555  * 
13556  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
13557  * </ul>
13558  *
13559  * If the constructor is called with another Persian date instance instead of
13560  * a parameter block, the other instance acts as a parameter block and its
13561  * settings are copied into the current instance.<p>
13562  * 
13563  * If the constructor is called with no arguments at all or if none of the 
13564  * properties listed above are present, then the RD is calculate based on 
13565  * the current date at the time of instantiation. <p>
13566  * 
13567  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
13568  * specified in the params, it is assumed that they have the smallest possible
13569  * value in the range for the property (zero or one).<p>
13570  * 
13571  * 
13572  * @private
13573  * @constructor
13574  * @extends RataDie
13575  * @param {Object=} params parameters that govern the settings and behaviour of this Persian RD date
13576  */
13577 var PersRataDie = function(params) {
13578 	this.rd = NaN;
13579 	Astro.initAstro(
13580 		params && typeof(params.sync) === 'boolean' ? params.sync : true,
13581 		params && params.loadParams,
13582 		ilib.bind(this, function (x) {
13583 			RataDie.call(this, params);
13584 			if (params && typeof(params.callback) === 'function') {
13585 				params.callback(this);
13586 			}
13587 		})
13588 	);
13589 };
13590 
13591 PersRataDie.prototype = new RataDie();
13592 PersRataDie.prototype.parent = RataDie;
13593 PersRataDie.prototype.constructor = PersRataDie;
13594 
13595 /**
13596  * The difference between a zero Julian day and the first Persian date
13597  * @private
13598  * @type number
13599  */
13600 PersRataDie.prototype.epoch = 1948319.5;
13601 
13602 /**
13603  * @protected 
13604  */
13605 PersRataDie.prototype._tehranEquinox = function(year) {
13606     var equJED, equJD, equAPP, equTehran, dtTehran, eot;
13607 
13608     //  March equinox in dynamical time
13609     equJED = Astro._equinox(year, 0);
13610 
13611     //  Correct for delta T to obtain Universal time
13612     equJD = equJED - (Astro._deltat(year) / (24 * 60 * 60));
13613 
13614     //  Apply the equation of time to yield the apparent time at Greenwich
13615     eot = Astro._equationOfTime(equJED) * 360;
13616     eot = (eot - 20 * Math.floor(eot/20)) / 360;
13617     equAPP = equJD + eot;
13618 
13619     /*  
13620      * Finally, we must correct for the constant difference between
13621      * the Greenwich meridian and the time zone standard for Iran 
13622      * Standard time, 52 degrees 30 minutes to the East.
13623      */
13624 
13625     dtTehran = 52.5 / 360;
13626     equTehran = equAPP + dtTehran;
13627 
13628     return equTehran;
13629 };
13630 
13631 /**
13632  * Calculate the year based on the given Julian day.
13633  * @protected
13634  * @param {number} jd the Julian day to get the year for
13635  * @return {{year:number,equinox:number}} the year and the last equinox
13636  */
13637 PersRataDie.prototype._getYear = function(jd) {
13638 	var gd = new GregorianDate({julianday: jd});
13639     var guess = gd.getYears() - 2,
13640     	nexteq,
13641     	ret = {};
13642 
13643     //ret.equinox = Math.floor(this._tehranEquinox(guess));
13644     ret.equinox = this._tehranEquinox(guess);
13645 	while (ret.equinox > jd) {
13646 	    guess--;
13647 	    // ret.equinox = Math.floor(this._tehranEquinox(guess));
13648 	    ret.equinox = this._tehranEquinox(guess);
13649 	}
13650 	nexteq = ret.equinox - 1;
13651 	// if the equinox falls after noon, then the day after that is the start of the 
13652 	// next year, so truncate the JD to get the noon of the day before the day with 
13653 	//the equinox on it, then add 0.5 to get the midnight of that day 
13654 	while (!(Math.floor(ret.equinox) + 0.5 <= jd && jd < Math.floor(nexteq) + 0.5)) {
13655 	    ret.equinox = nexteq;
13656 	    guess++;
13657 	    // nexteq = Math.floor(this._tehranEquinox(guess));
13658 	    nexteq = this._tehranEquinox(guess);
13659 	}
13660 	
13661 	// Mean solar tropical year is 365.24219878 days
13662 	ret.year = Math.round((ret.equinox - this.epoch - 1) / 365.24219878) + 1;
13663 	
13664 	return ret;
13665 };
13666 
13667 /**
13668  * Calculate the Rata Die (fixed day) number of the given date from the
13669  * date components.
13670  *
13671  * @protected
13672  * @param {Object} date the date components to calculate the RD from
13673  */
13674 PersRataDie.prototype._setDateComponents = function(date) {
13675     var adr, guess, jd;
13676 
13677     // Mean solar tropical year is 365.24219878 days 
13678     guess = this.epoch + 1 + 365.24219878 * (date.year - 2);
13679     adr = {year: date.year - 1, equinox: 0};
13680 
13681     while (adr.year < date.year) {
13682         adr = this._getYear(guess);
13683         guess = adr.equinox + (365.24219878 + 2);
13684     }
13685 
13686     jd = Math.floor(adr.equinox) +
13687             ((date.month <= 7) ?
13688                 ((date.month - 1) * 31) :
13689                 (((date.month - 1) * 30) + 6)
13690             ) +
13691     	    (date.day - 1 + 0.5); // add 0.5 so that we convert JDs, which start at noon to RDs which start at midnight
13692     
13693 	jd += (date.hour * 3600000 +
13694 			date.minute * 60000 +
13695 			date.second * 1000 +
13696 			date.millisecond) /
13697 			86400000;
13698 
13699     this.rd = jd - this.epoch;
13700 };
13701 
13702 /**
13703  * Return the rd number of the particular day of the week on or before the 
13704  * given rd. eg. The Sunday on or before the given rd.
13705  * @private
13706  * @param {number} rd the rata die date of the reference date
13707  * @param {number} dayOfWeek the day of the week that is being sought relative 
13708  * to the current date
13709  * @return {number} the rd of the day of the week
13710  */
13711 PersRataDie.prototype._onOrBefore = function(rd, dayOfWeek) {
13712 	return rd - MathUtils.mod(Math.floor(rd) - dayOfWeek - 3, 7);
13713 };
13714 
13715 
13716 /*< PersianCal.js */
13717 /*
13718  * persianastro.js - Represent a Persian astronomical (Hijjri) calendar object.
13719  * 
13720  * Copyright © 2014-2015, JEDLSoft
13721  *
13722  * Licensed under the Apache License, Version 2.0 (the "License");
13723  * you may not use this file except in compliance with the License.
13724  * You may obtain a copy of the License at
13725  *
13726  *     http://www.apache.org/licenses/LICENSE-2.0
13727  *
13728  * Unless required by applicable law or agreed to in writing, software
13729  * distributed under the License is distributed on an "AS IS" BASIS,
13730  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13731  *
13732  * See the License for the specific language governing permissions and
13733  * limitations under the License.
13734  */
13735 
13736 
13737 /* !depends 
13738 Calendar.js 
13739 PersRataDie.js 
13740 ilib.js
13741 MathUtils.js
13742 */
13743 
13744 
13745 
13746 
13747 /**
13748  * @class
13749  * Construct a new Persian astronomical (Hijjri) calendar object. This class encodes 
13750  * information about a Persian calendar. This class differs from the 
13751  * Persian calendar in that the leap years are calculated based on the
13752  * astronomical observations of the sun in Teheran, instead of calculating
13753  * the leap years based on a regular cyclical rhythm algorithm.<p>
13754  * 
13755  * 
13756  * @constructor
13757  * @extends Calendar
13758  */
13759 var PersianCal = function() {
13760 	this.type = "persian";
13761 };
13762 
13763 /**
13764  * @private
13765  * @const
13766  * @type Array.<number> 
13767  * the lengths of each month 
13768  */
13769 PersianCal.monthLengths = [
13770 	31,  // Farvardin
13771 	31,  // Ordibehesht
13772 	31,  // Khordad
13773 	31,  // Tir
13774 	31,  // Mordad
13775 	31,  // Shahrivar
13776 	30,  // Mehr
13777 	30,  // Aban
13778 	30,  // Azar
13779 	30,  // Dey
13780 	30,  // Bahman
13781 	29   // Esfand
13782 ];
13783 
13784 /**
13785  * Return the number of months in the given year. The number of months in a year varies
13786  * for some luni-solar calendars because in some years, an extra month is needed to extend the 
13787  * days in a year to an entire solar year. The month is represented as a 1-based number
13788  * where 1=first month, 2=second month, etc.
13789  * 
13790  * @param {number} year a year for which the number of months is sought
13791  * @return {number} The number of months in the given year
13792  */
13793 PersianCal.prototype.getNumMonths = function(year) {
13794 	return 12;
13795 };
13796 
13797 /**
13798  * Return the number of days in a particular month in a particular year. This function
13799  * can return a different number for a month depending on the year because of things
13800  * like leap years.
13801  * 
13802  * @param {number} month the month for which the length is sought
13803  * @param {number} year the year within which that month can be found
13804  * @return {number} the number of days within the given month in the given year
13805  */
13806 PersianCal.prototype.getMonLength = function(month, year) {
13807 	if (month !== 12 || !this.isLeapYear(year)) {
13808 		return PersianCal.monthLengths[month-1];
13809 	} else {
13810 		// Month 12, Esfand, has 30 days instead of 29 in leap years
13811 		return 30;
13812 	}
13813 };
13814 
13815 /**
13816  * Return true if the given year is a leap year in the Persian astronomical calendar.
13817  * @param {number} year the year for which the leap year information is being sought
13818  * @return {boolean} true if the given year is a leap year
13819  */
13820 PersianCal.prototype.isLeapYear = function(year) {
13821 	var rdNextYear = new PersRataDie({
13822 		cal: this,
13823 		year: year + 1,
13824 		month: 1,
13825 		day: 1,
13826 		hour: 0,
13827 		minute: 0,
13828 		second: 0,
13829 		millisecond: 0
13830 	});
13831 	var rdThisYear = new PersRataDie({
13832 		cal: this,
13833 		year: year,
13834 		month: 1,
13835 		day: 1,
13836 		hour: 0,
13837 		minute: 0,
13838 		second: 0,
13839 		millisecond: 0
13840 	}); 
13841     return (rdNextYear.getRataDie() - rdThisYear.getRataDie()) > 365;
13842 };
13843 
13844 /**
13845  * Return the type of this calendar.
13846  * 
13847  * @return {string} the name of the type of this calendar 
13848  */
13849 PersianCal.prototype.getType = function() {
13850 	return this.type;
13851 };
13852 
13853 /**
13854  * Return a date instance for this calendar type using the given
13855  * options.
13856  * @param {Object} options options controlling the construction of 
13857  * the date instance
13858  * @return {IDate} a date appropriate for this calendar type
13859  * @deprecated Since 11.0.5. Use DateFactory({calendar: cal.getType(), ...}) instead
13860  */
13861 PersianCal.prototype.newDateInstance = function (options) {
13862 		return new PersianDate(options);
13863 };
13864 
13865 /* register this calendar for the factory method */
13866 Calendar._constructors["persian"] = PersianCal;
13867 
13868 
13869 /*< PersianDate.js */
13870 /*
13871  * PersianDate.js - Represent a date in the Persian astronomical (Hijjri) calendar
13872  * 
13873  * Copyright © 2014-2015, JEDLSoft
13874  *
13875  * Licensed under the Apache License, Version 2.0 (the "License");
13876  * you may not use this file except in compliance with the License.
13877  * You may obtain a copy of the License at
13878  *
13879  *     http://www.apache.org/licenses/LICENSE-2.0
13880  *
13881  * Unless required by applicable law or agreed to in writing, software
13882  * distributed under the License is distributed on an "AS IS" BASIS,
13883  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13884  *
13885  * See the License for the specific language governing permissions and
13886  * limitations under the License.
13887  */
13888 
13889 /* !depends 
13890 ilib.js
13891 Locale.js
13892 TimeZone.js
13893 IDate.js
13894 PersRataDie.js
13895 PersianCal.js 
13896 SearchUtils.js
13897 MathUtils.js
13898 LocaleInfo.js 
13899 Astro.js
13900 */
13901 
13902 // !data astro
13903 
13904 
13905 
13906 
13907 /**
13908  * @class
13909  * 
13910  * Construct a new Persian astronomical date object. The constructor parameters can 
13911  * contain any of the following properties:
13912  * 
13913  * <ul>
13914  * <li><i>unixtime<i> - sets the time of this instance according to the given 
13915  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970, Gregorian
13916  * 
13917  * <li><i>julianday</i> - sets the time of this instance according to the given
13918  * Julian Day instance or the Julian Day given as a float
13919  * 
13920  * <li><i>year</i> - any integer, including 0
13921  * 
13922  * <li><i>month</i> - 1 to 12, where 1 means Farvardin, 2 means Ordibehesht, etc.
13923  * 
13924  * <li><i>day</i> - 1 to 31
13925  * 
13926  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
13927  * is always done with an unambiguous 24 hour representation
13928  * 
13929  * <li><i>minute</i> - 0 to 59
13930  * 
13931  * <li><i>second</i> - 0 to 59
13932  * 
13933  * <li><i>millisecond</i> - 0 to 999
13934  * 
13935  * <li><i>timezone</i> - the TimeZone instance or time zone name as a string 
13936  * of this persian date. The date/time is kept in the local time. The time zone
13937  * is used later if this date is formatted according to a different time zone and
13938  * the difference has to be calculated, or when the date format has a time zone
13939  * component in it.
13940  * 
13941  * <li><i>locale</i> - locale for this persian date. If the time zone is not 
13942  * given, it can be inferred from this locale. For locales that span multiple
13943  * time zones, the one with the largest population is chosen as the one that 
13944  * represents the locale.
13945  * 
13946  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
13947  * </ul>
13948  *
13949  * If the constructor is called with another Persian date instance instead of
13950  * a parameter block, the other instance acts as a parameter block and its
13951  * settings are copied into the current instance.<p>
13952  * 
13953  * If the constructor is called with no arguments at all or if none of the 
13954  * properties listed above 
13955  * from <i>unixtime</i> through <i>millisecond</i> are present, then the date 
13956  * components are 
13957  * filled in with the current date at the time of instantiation. Note that if
13958  * you do not give the time zone when defaulting to the current time and the 
13959  * time zone for all of ilib was not set with <i>ilib.setTimeZone()</i>, then the
13960  * time zone will default to UTC ("Universal Time, Coordinated" or "Greenwich 
13961  * Mean Time").<p>
13962  * 
13963  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
13964  * specified in the params, it is assumed that they have the smallest possible
13965  * value in the range for the property (zero or one).<p>
13966  * 
13967  * 
13968  * @constructor
13969  * @extends IDate
13970  * @param {Object=} params parameters that govern the settings and behaviour of this Persian date
13971  */
13972 var PersianDate = function(params) {
13973 	this.cal = new PersianCal();
13974 	this.timezone = "local";
13975 	
13976 	if (params) {
13977 		if (params.locale) {
13978 			this.locale = (typeof(params.locale) === 'string') ? new Locale(params.locale) : params.locale;
13979 			var li = new LocaleInfo(this.locale);
13980 			this.timezone = li.getTimeZone(); 
13981 		}
13982 		if (params.timezone) {
13983 			this.timezone = params.timezone;
13984 		}
13985 	}
13986 	
13987 	Astro.initAstro(
13988 		params && typeof(params.sync) === 'boolean' ? params.sync : true,
13989 		params && params.loadParams,
13990 		ilib.bind(this, function (x) {
13991 			if (params && (params.year || params.month || params.day || params.hour ||
13992 					params.minute || params.second || params.millisecond)) {
13993 				/**
13994 				 * Year in the Persian calendar.
13995 				 * @type number
13996 				 */
13997 				this.year = parseInt(params.year, 10) || 0;
13998 
13999 				/**
14000 				 * The month number, ranging from 1 to 12
14001 				 * @type number
14002 				 */
14003 				this.month = parseInt(params.month, 10) || 1;
14004 
14005 				/**
14006 				 * The day of the month. This ranges from 1 to 31.
14007 				 * @type number
14008 				 */
14009 				this.day = parseInt(params.day, 10) || 1;
14010 				
14011 				/**
14012 				 * The hour of the day. This can be a number from 0 to 23, as times are
14013 				 * stored unambiguously in the 24-hour clock.
14014 				 * @type number
14015 				 */
14016 				this.hour = parseInt(params.hour, 10) || 0;
14017 
14018 				/**
14019 				 * The minute of the hours. Ranges from 0 to 59.
14020 				 * @type number
14021 				 */
14022 				this.minute = parseInt(params.minute, 10) || 0;
14023 
14024 				/**
14025 				 * The second of the minute. Ranges from 0 to 59.
14026 				 * @type number
14027 				 */
14028 				this.second = parseInt(params.second, 10) || 0;
14029 
14030 				/**
14031 				 * The millisecond of the second. Ranges from 0 to 999.
14032 				 * @type number
14033 				 */
14034 				this.millisecond = parseInt(params.millisecond, 10) || 0;
14035 				
14036 				/**
14037 				 * The day of the year. Ranges from 1 to 366.
14038 				 * @type number
14039 				 */
14040 				this.dayOfYear = parseInt(params.dayOfYear, 10);
14041 
14042 				if (typeof(params.dst) === 'boolean') {
14043 					this.dst = params.dst;
14044 				}
14045 				
14046 				this.rd = this.newRd(this);
14047 				
14048 				// add the time zone offset to the rd to convert to UTC
14049 				if (!this.tz) {
14050 					this.tz = new TimeZone({id: this.timezone});
14051 				}
14052 				// getOffsetMillis requires that this.year, this.rd, and this.dst 
14053 				// are set in order to figure out which time zone rules apply and 
14054 				// what the offset is at that point in the year
14055 				this.offset = this.tz._getOffsetMillisWallTime(this) / 86400000;
14056 				if (this.offset !== 0) {
14057 					this.rd = this.newRd({
14058 						rd: this.rd.getRataDie() - this.offset
14059 					});
14060 				}
14061 			}
14062 			
14063 			if (!this.rd) {
14064 				this.rd = this.newRd(params);
14065 				this._calcDateComponents();
14066 			}
14067 			
14068 			if (params && typeof(params.onLoad) === 'function') {
14069 				params.onLoad(this);
14070 			}
14071 		})
14072 	);
14073 };
14074 
14075 PersianDate.prototype = new IDate({noinstance: true});
14076 PersianDate.prototype.parent = IDate;
14077 PersianDate.prototype.constructor = PersianDate;
14078 
14079 /**
14080  * @private
14081  * @const
14082  * @type Array.<number>
14083  * the cumulative lengths of each month, for a non-leap year 
14084  */
14085 PersianDate.cumMonthLengths = [
14086     0,    // Farvardin
14087 	31,   // Ordibehesht
14088 	62,   // Khordad
14089 	93,   // Tir
14090 	124,  // Mordad
14091 	155,  // Shahrivar
14092 	186,  // Mehr
14093 	216,  // Aban
14094 	246,  // Azar
14095 	276,  // Dey
14096 	306,  // Bahman
14097 	336,  // Esfand
14098 	366
14099 ];
14100 
14101 /**
14102  * Return a new RD for this date type using the given params.
14103  * @protected
14104  * @param {Object=} params the parameters used to create this rata die instance
14105  * @returns {RataDie} the new RD instance for the given params
14106  */
14107 PersianDate.prototype.newRd = function (params) {
14108 	return new PersRataDie(params);
14109 };
14110 
14111 /**
14112  * Return the year for the given RD
14113  * @protected
14114  * @param {number} rd RD to calculate from 
14115  * @returns {number} the year for the RD
14116  */
14117 PersianDate.prototype._calcYear = function(rd) {
14118 	var julianday = rd + this.rd.epoch;
14119 	return this.rd._getYear(julianday).year;
14120 };
14121 
14122 /**
14123  * @private
14124  * Calculate date components for the given RD date.
14125  */
14126 PersianDate.prototype._calcDateComponents = function () {
14127 	var remainder,
14128 		rd = this.rd.getRataDie();
14129 	
14130 	this.year = this._calcYear(rd);
14131 	
14132 	if (typeof(this.offset) === "undefined") {
14133 		// now offset the RD by the time zone, then recalculate in case we were 
14134 		// near the year boundary
14135 		if (!this.tz) {
14136 			this.tz = new TimeZone({id: this.timezone});
14137 		}
14138 		this.offset = this.tz.getOffsetMillis(this) / 86400000;
14139 	}
14140 	
14141 	if (this.offset !== 0) {
14142 		rd += this.offset;
14143 		this.year = this._calcYear(rd);
14144 	}
14145 	
14146 	//console.log("PersDate.calcComponent: calculating for rd " + rd);
14147 	//console.log("PersDate.calcComponent: year is " + ret.year);
14148 	var yearStart = this.newRd({
14149 		year: this.year,
14150 		month: 1,
14151 		day: 1,
14152 		hour: 0,
14153 		minute: 0,
14154 		second: 0,
14155 		millisecond: 0
14156 	});
14157 	remainder = rd - yearStart.getRataDie() + 1;
14158 	
14159 	this.dayOfYear = remainder;
14160 	
14161 	//console.log("PersDate.calcComponent: remainder is " + remainder);
14162 	
14163 	this.month = SearchUtils.bsearch(Math.floor(remainder), PersianDate.cumMonthLengths);
14164 	remainder -= PersianDate.cumMonthLengths[this.month-1];
14165 	
14166 	//console.log("PersDate.calcComponent: month is " + this.month + " and remainder is " + remainder);
14167 	
14168 	this.day = Math.floor(remainder);
14169 	remainder -= this.day;
14170 	
14171 	//console.log("PersDate.calcComponent: day is " + this.day + " and remainder is " + remainder);
14172 	
14173 	// now convert to milliseconds for the rest of the calculation
14174 	remainder = Math.round(remainder * 86400000);
14175 	
14176 	this.hour = Math.floor(remainder/3600000);
14177 	remainder -= this.hour * 3600000;
14178 	
14179 	this.minute = Math.floor(remainder/60000);
14180 	remainder -= this.minute * 60000;
14181 	
14182 	this.second = Math.floor(remainder/1000);
14183 	remainder -= this.second * 1000;
14184 	
14185 	this.millisecond = remainder;
14186 };
14187 
14188 /**
14189  * Return the day of the week of this date. The day of the week is encoded
14190  * as number from 0 to 6, with 0=Sunday, 1=Monday, etc., until 6=Saturday.
14191  * 
14192  * @return {number} the day of the week
14193  */
14194 PersianDate.prototype.getDayOfWeek = function() {
14195 	var rd = Math.floor(this.getRataDie());
14196 	return MathUtils.mod(rd-3, 7);
14197 };
14198 
14199 /**
14200  * Return the ordinal day of the year. Days are counted from 1 and proceed linearly up to 
14201  * 365, regardless of months or weeks, etc. That is, Farvardin 1st is day 1, and 
14202  * December 31st is 365 in regular years, or 366 in leap years.
14203  * @return {number} the ordinal day of the year
14204  */
14205 PersianDate.prototype.getDayOfYear = function() {
14206 	return PersianDate.cumMonthLengths[this.month-1] + this.day;
14207 };
14208 
14209 /**
14210  * Return the era for this date as a number. The value for the era for Persian 
14211  * calendars is -1 for "before the persian era" (BP) and 1 for "the persian era" (anno 
14212  * persico or AP). 
14213  * BP dates are any date before Farvardin 1, 1 AP. In the proleptic Persian calendar, 
14214  * there is a year 0, so any years that are negative or zero are BP.
14215  * @return {number} 1 if this date is in the common era, -1 if it is before the 
14216  * common era 
14217  */
14218 PersianDate.prototype.getEra = function() {
14219 	return (this.year < 1) ? -1 : 1;
14220 };
14221 
14222 /**
14223  * Return the name of the calendar that governs this date.
14224  * 
14225  * @return {string} a string giving the name of the calendar
14226  */
14227 PersianDate.prototype.getCalendar = function() {
14228 	return "persian";
14229 };
14230 
14231 // register with the factory method
14232 IDate._constructors["persian"] = PersianDate;
14233 
14234 
14235 /*< PersianAlgoCal.js */
14236 /*
14237  * persian.js - Represent a Persian algorithmic calendar object.
14238  * 
14239  * Copyright © 2014-2015, JEDLSoft
14240  *
14241  * Licensed under the Apache License, Version 2.0 (the "License");
14242  * you may not use this file except in compliance with the License.
14243  * You may obtain a copy of the License at
14244  *
14245  *     http://www.apache.org/licenses/LICENSE-2.0
14246  *
14247  * Unless required by applicable law or agreed to in writing, software
14248  * distributed under the License is distributed on an "AS IS" BASIS,
14249  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14250  *
14251  * See the License for the specific language governing permissions and
14252  * limitations under the License.
14253  */
14254 
14255 
14256 /* !depends ilib.js Calendar.js MathUtils.js */
14257 
14258 
14259 /**
14260  * @class
14261  * Construct a new Persian algorithmic calendar object. This class encodes information about
14262  * a Persian algorithmic calendar.<p>
14263  * 
14264  * 
14265  * @constructor
14266  * @extends Calendar
14267  */
14268 var PersianAlgoCal = function() {
14269 	this.type = "persian-algo";
14270 };
14271 
14272 /**
14273  * @private
14274  * @const
14275  * @type Array.<number> 
14276  * the lengths of each month 
14277  */
14278 PersianAlgoCal.monthLengths = [
14279 	31,  // Farvardin
14280 	31,  // Ordibehesht
14281 	31,  // Khordad
14282 	31,  // Tir
14283 	31,  // Mordad
14284 	31,  // Shahrivar
14285 	30,  // Mehr
14286 	30,  // Aban
14287 	30,  // Azar
14288 	30,  // Dey
14289 	30,  // Bahman
14290 	29   // Esfand
14291 ];
14292 
14293 /**
14294  * Return the number of months in the given year. The number of months in a year varies
14295  * for some luni-solar calendars because in some years, an extra month is needed to extend the 
14296  * days in a year to an entire solar year. The month is represented as a 1-based number
14297  * where 1=first month, 2=second month, etc.
14298  * 
14299  * @param {number} year a year for which the number of months is sought
14300  * @return {number} The number of months in the given year
14301  */
14302 PersianAlgoCal.prototype.getNumMonths = function(year) {
14303 	return 12;
14304 };
14305 
14306 /**
14307  * Return the number of days in a particular month in a particular year. This function
14308  * can return a different number for a month depending on the year because of things
14309  * like leap years.
14310  * 
14311  * @param {number} month the month for which the length is sought
14312  * @param {number} year the year within which that month can be found
14313  * @return {number} the number of days within the given month in the given year
14314  */
14315 PersianAlgoCal.prototype.getMonLength = function(month, year) {
14316 	if (month !== 12 || !this.isLeapYear(year)) {
14317 		return PersianAlgoCal.monthLengths[month-1];
14318 	} else {
14319 		// Month 12, Esfand, has 30 days instead of 29 in leap years
14320 		return 30;
14321 	}
14322 };
14323 
14324 /**
14325  * Return the equivalent year in the 2820 year cycle that begins on 
14326  * Far 1, 474. This particular cycle obeys the cycle-of-years formula 
14327  * whereas the others do not specifically. This cycle can be used as
14328  * a proxy for other years outside of the cycle by shifting them into 
14329  * the cycle.   
14330  * @param {number} year year to find the equivalent cycle year for
14331  * @returns {number} the equivalent cycle year
14332  */
14333 PersianAlgoCal.prototype.equivalentCycleYear = function(year) {
14334 	var y = year - (year >= 0 ? 474 : 473);
14335 	return MathUtils.mod(y, 2820) + 474;
14336 };
14337 
14338 /**
14339  * Return true if the given year is a leap year in the Persian calendar.
14340  * The year parameter may be given as a number, or as a PersAlgoDate object.
14341  * @param {number} year the year for which the leap year information is being sought
14342  * @return {boolean} true if the given year is a leap year
14343  */
14344 PersianAlgoCal.prototype.isLeapYear = function(year) {
14345 	return (MathUtils.mod((this.equivalentCycleYear(year) + 38) * 682, 2816) < 682);
14346 };
14347 
14348 /**
14349  * Return the type of this calendar.
14350  * 
14351  * @return {string} the name of the type of this calendar 
14352  */
14353 PersianAlgoCal.prototype.getType = function() {
14354 	return this.type;
14355 };
14356 
14357 /**
14358  * Return a date instance for this calendar type using the given
14359  * options.
14360  * @param {Object} options options controlling the construction of 
14361  * the date instance
14362  * @return {IDate} a date appropriate for this calendar type
14363  * @deprecated Since 11.0.5. Use DateFactory({calendar: cal.getType(), ...}) instead
14364  */
14365 PersianAlgoCal.prototype.newDateInstance = function (options) {
14366 		return new PersianAlgoDate(options);
14367 };
14368 
14369 /* register this calendar for the factory method */
14370 Calendar._constructors["persian-algo"] = PersianAlgoCal;
14371 
14372 
14373 /*< PersAlgoRataDie.js */
14374 /*
14375  * PersAlsoRataDie.js - Represent an RD date in the Persian algorithmic calendar
14376  * 
14377  * Copyright © 2014-2015, JEDLSoft
14378  *
14379  * Licensed under the Apache License, Version 2.0 (the "License");
14380  * you may not use this file except in compliance with the License.
14381  * You may obtain a copy of the License at
14382  *
14383  *     http://www.apache.org/licenses/LICENSE-2.0
14384  *
14385  * Unless required by applicable law or agreed to in writing, software
14386  * distributed under the License is distributed on an "AS IS" BASIS,
14387  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14388  *
14389  * See the License for the specific language governing permissions and
14390  * limitations under the License.
14391  */
14392 
14393 /* !depends 
14394 PersianAlgoCal.js 
14395 MathUtils.js
14396 RataDie.js
14397 */
14398 
14399 
14400 /**
14401  * @class
14402  * Construct a new Persian RD date number object. The constructor parameters can 
14403  * contain any of the following properties:
14404  * 
14405  * <ul>
14406  * <li><i>unixtime<i> - sets the time of this instance according to the given 
14407  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970, Gregorian
14408  * 
14409  * <li><i>julianday</i> - sets the time of this instance according to the given
14410  * Julian Day instance or the Julian Day given as a float
14411  * 
14412  * <li><i>year</i> - any integer, including 0
14413  * 
14414  * <li><i>month</i> - 1 to 12, where 1 means Farvardin, 2 means Ordibehesht, etc.
14415  * 
14416  * <li><i>day</i> - 1 to 31
14417  * 
14418  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
14419  * is always done with an unambiguous 24 hour representation
14420  * 
14421  * <li><i>minute</i> - 0 to 59
14422  * 
14423  * <li><i>second</i> - 0 to 59
14424  * 
14425  * <li><i>millisecond</i> - 0 to 999
14426  * 
14427  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
14428  * </ul>
14429  *
14430  * If the constructor is called with another Persian date instance instead of
14431  * a parameter block, the other instance acts as a parameter block and its
14432  * settings are copied into the current instance.<p>
14433  * 
14434  * If the constructor is called with no arguments at all or if none of the 
14435  * properties listed above are present, then the RD is calculate based on 
14436  * the current date at the time of instantiation. <p>
14437  * 
14438  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
14439  * specified in the params, it is assumed that they have the smallest possible
14440  * value in the range for the property (zero or one).<p>
14441  * 
14442  * 
14443  * @private
14444  * @constructor
14445  * @extends RataDie
14446  * @param {Object=} params parameters that govern the settings and behaviour of this Persian RD date
14447  */
14448 var PersAlgoRataDie = function(params) {
14449 	this.cal = params && params.cal || new PersianAlgoCal();
14450 	this.rd = NaN;
14451 	RataDie.call(this, params);
14452 };
14453 
14454 PersAlgoRataDie.prototype = new RataDie();
14455 PersAlgoRataDie.prototype.parent = RataDie;
14456 PersAlgoRataDie.prototype.constructor = PersAlgoRataDie;
14457 
14458 /**
14459  * The difference between a zero Julian day and the first Persian date
14460  * @private
14461  * @type number
14462  */
14463 PersAlgoRataDie.prototype.epoch = 1948319.5;
14464 
14465 /**
14466  * @private
14467  * @const
14468  * @type Array.<number>
14469  * the cumulative lengths of each month, for a non-leap year 
14470  */
14471 PersAlgoRataDie.cumMonthLengths = [
14472     0,    // Farvardin
14473 	31,   // Ordibehesht
14474 	62,   // Khordad
14475 	93,   // Tir
14476 	124,  // Mordad
14477 	155,  // Shahrivar
14478 	186,  // Mehr
14479 	216,  // Aban
14480 	246,  // Azar
14481 	276,  // Dey
14482 	306,  // Bahman
14483 	336,  // Esfand
14484 	365
14485 ];
14486 
14487 /**
14488  * Calculate the Rata Die (fixed day) number of the given date from the
14489  * date components.
14490  *
14491  * @protected
14492  * @param {Object} date the date components to calculate the RD from
14493  */
14494 PersAlgoRataDie.prototype._setDateComponents = function(date) {
14495 	var year = this.cal.equivalentCycleYear(date.year);
14496 	var y = date.year - (date.year >= 0 ? 474 : 473);
14497 	var rdOfYears = 1029983 * Math.floor(y/2820) + 365 * (year - 1) + Math.floor((682 * year - 110) / 2816);
14498 	var dayInYear = (date.month > 1 ? PersAlgoRataDie.cumMonthLengths[date.month-1] : 0) + date.day;
14499 	var rdtime = (date.hour * 3600000 +
14500 		date.minute * 60000 +
14501 		date.second * 1000 +
14502 		date.millisecond) /
14503 		86400000;
14504 	
14505 	/*
14506 	// console.log("getRataDie: converting " +  JSON.stringify(this));
14507 	console.log("getRataDie: year is " +  year);
14508 	console.log("getRataDie: rd of years is " +  rdOfYears);
14509 	console.log("getRataDie: day in year is " +  dayInYear);
14510 	console.log("getRataDie: rdtime is " +  rdtime);
14511 	console.log("getRataDie: rd is " +  (rdOfYears + dayInYear + rdtime));
14512 	*/
14513 	
14514 	this.rd = rdOfYears + dayInYear + rdtime;
14515 };
14516 
14517 /**
14518  * Return the rd number of the particular day of the week on or before the 
14519  * given rd. eg. The Sunday on or before the given rd.
14520  * @private
14521  * @param {number} rd the rata die date of the reference date
14522  * @param {number} dayOfWeek the day of the week that is being sought relative 
14523  * to the current date
14524  * @return {number} the rd of the day of the week
14525  */
14526 PersAlgoRataDie.prototype._onOrBefore = function(rd, dayOfWeek) {
14527 	return rd - MathUtils.mod(Math.floor(rd) - dayOfWeek - 3, 7);
14528 };
14529 
14530 
14531 /*< PersianAlgoDate.js */
14532 /*
14533  * PersianAlgoDate.js - Represent a date in the Persian algorithmic calendar
14534  * 
14535  * Copyright © 2014-2015, JEDLSoft
14536  *
14537  * Licensed under the Apache License, Version 2.0 (the "License");
14538  * you may not use this file except in compliance with the License.
14539  * You may obtain a copy of the License at
14540  *
14541  *     http://www.apache.org/licenses/LICENSE-2.0
14542  *
14543  * Unless required by applicable law or agreed to in writing, software
14544  * distributed under the License is distributed on an "AS IS" BASIS,
14545  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14546  *
14547  * See the License for the specific language governing permissions and
14548  * limitations under the License.
14549  */
14550 
14551 /* !depends 
14552 ilib.js
14553 Locale.js
14554 LocaleInfo.js
14555 TimeZone.js
14556 IDate.js
14557 PersianAlgoCal.js 
14558 SearchUtils.js
14559 MathUtils.js
14560 PersAlgoRataDie.js
14561 */
14562 
14563 
14564 
14565 
14566 /**
14567  * @class
14568  * 
14569  * Construct a new Persian date object. The constructor parameters can 
14570  * contain any of the following properties:
14571  * 
14572  * <ul>
14573  * <li><i>unixtime<i> - sets the time of this instance according to the given 
14574  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970, Gregorian
14575  * 
14576  * <li><i>julianday</i> - sets the time of this instance according to the given
14577  * Julian Day instance or the Julian Day given as a float
14578  * 
14579  * <li><i>year</i> - any integer, including 0
14580  * 
14581  * <li><i>month</i> - 1 to 12, where 1 means Farvardin, 2 means Ordibehesht, etc.
14582  * 
14583  * <li><i>day</i> - 1 to 31
14584  * 
14585  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
14586  * is always done with an unambiguous 24 hour representation
14587  * 
14588  * <li><i>minute</i> - 0 to 59
14589  * 
14590  * <li><i>second</i> - 0 to 59
14591  * 
14592  * <li><i>millisecond</i> - 0 to 999
14593  * 
14594  * <li><i>timezone</i> - the TimeZone instance or time zone name as a string 
14595  * of this persian date. The date/time is kept in the local time. The time zone
14596  * is used later if this date is formatted according to a different time zone and
14597  * the difference has to be calculated, or when the date format has a time zone
14598  * component in it.
14599  * 
14600  * <li><i>locale</i> - locale for this persian date. If the time zone is not 
14601  * given, it can be inferred from this locale. For locales that span multiple
14602  * time zones, the one with the largest population is chosen as the one that 
14603  * represents the locale.
14604  * 
14605  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
14606  * </ul>
14607  *
14608  * If the constructor is called with another Persian date instance instead of
14609  * a parameter block, the other instance acts as a parameter block and its
14610  * settings are copied into the current instance.<p>
14611  * 
14612  * If the constructor is called with no arguments at all or if none of the 
14613  * properties listed above 
14614  * from <i>unixtime</i> through <i>millisecond</i> are present, then the date 
14615  * components are 
14616  * filled in with the current date at the time of instantiation. Note that if
14617  * you do not give the time zone when defaulting to the current time and the 
14618  * time zone for all of ilib was not set with <i>ilib.setTimeZone()</i>, then the
14619  * time zone will default to UTC ("Universal Time, Coordinated" or "Greenwich 
14620  * Mean Time").<p>
14621  * 
14622  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
14623  * specified in the params, it is assumed that they have the smallest possible
14624  * value in the range for the property (zero or one).<p>
14625  * 
14626  * 
14627  * @constructor
14628  * @extends IDate
14629  * @param {Object=} params parameters that govern the settings and behaviour of this Persian date
14630  */
14631 var PersianAlgoDate = function(params) {
14632 	this.cal = new PersianAlgoCal();
14633 	this.timezone = "local";
14634 	
14635 	if (params) {
14636 		if (params.locale) {
14637 			this.locale = (typeof(params.locale) === 'string') ? new Locale(params.locale) : params.locale;
14638 			var li = new LocaleInfo(this.locale);
14639 			this.timezone = li.getTimeZone(); 
14640 		}
14641 		if (params.timezone) {
14642 			this.timezone = params.timezone;
14643 		}
14644 		
14645 		if (params.year || params.month || params.day || params.hour ||
14646 				params.minute || params.second || params.millisecond ) {
14647 			/**
14648 			 * Year in the Persian calendar.
14649 			 * @type number
14650 			 */
14651 			this.year = parseInt(params.year, 10) || 0;
14652 
14653 			/**
14654 			 * The month number, ranging from 1 to 12
14655 			 * @type number
14656 			 */
14657 			this.month = parseInt(params.month, 10) || 1;
14658 
14659 			/**
14660 			 * The day of the month. This ranges from 1 to 31.
14661 			 * @type number
14662 			 */
14663 			this.day = parseInt(params.day, 10) || 1;
14664 			
14665 			/**
14666 			 * The hour of the day. This can be a number from 0 to 23, as times are
14667 			 * stored unambiguously in the 24-hour clock.
14668 			 * @type number
14669 			 */
14670 			this.hour = parseInt(params.hour, 10) || 0;
14671 
14672 			/**
14673 			 * The minute of the hours. Ranges from 0 to 59.
14674 			 * @type number
14675 			 */
14676 			this.minute = parseInt(params.minute, 10) || 0;
14677 
14678 			/**
14679 			 * The second of the minute. Ranges from 0 to 59.
14680 			 * @type number
14681 			 */
14682 			this.second = parseInt(params.second, 10) || 0;
14683 
14684 			/**
14685 			 * The millisecond of the second. Ranges from 0 to 999.
14686 			 * @type number
14687 			 */
14688 			this.millisecond = parseInt(params.millisecond, 10) || 0;
14689 			
14690 			/**
14691 			 * The day of the year. Ranges from 1 to 366.
14692 			 * @type number
14693 			 */
14694 			this.dayOfYear = parseInt(params.dayOfYear, 10);
14695 
14696 			if (typeof(params.dst) === 'boolean') {
14697 				this.dst = params.dst;
14698 			}
14699 			
14700 			this.rd = this.newRd(this);
14701 			
14702 			// add the time zone offset to the rd to convert to UTC
14703 			if (!this.tz) {
14704 				this.tz = new TimeZone({id: this.timezone});
14705 			}
14706 			// getOffsetMillis requires that this.year, this.rd, and this.dst 
14707 			// are set in order to figure out which time zone rules apply and 
14708 			// what the offset is at that point in the year
14709 			this.offset = this.tz._getOffsetMillisWallTime(this) / 86400000;
14710 			if (this.offset !== 0) {
14711 				this.rd = this.newRd({
14712 					rd: this.rd.getRataDie() - this.offset
14713 				});
14714 			}
14715 		}
14716 	}
14717 
14718 	if (!this.rd) {
14719 		this.rd = this.newRd(params);
14720 		this._calcDateComponents();
14721 	}
14722 };
14723 
14724 PersianAlgoDate.prototype = new IDate({noinstance: true});
14725 PersianAlgoDate.prototype.parent = IDate;
14726 PersianAlgoDate.prototype.constructor = PersianAlgoDate;
14727 
14728 /**
14729  * Return a new RD for this date type using the given params.
14730  * @protected
14731  * @param {Object=} params the parameters used to create this rata die instance
14732  * @returns {RataDie} the new RD instance for the given params
14733  */
14734 PersianAlgoDate.prototype.newRd = function (params) {
14735 	return new PersAlgoRataDie(params);
14736 };
14737 
14738 /**
14739  * Return the year for the given RD
14740  * @protected
14741  * @param {number} rd RD to calculate from 
14742  * @returns {number} the year for the RD
14743  */
14744 PersianAlgoDate.prototype._calcYear = function(rd) {
14745 	var shiftedRd = rd - 173126;
14746 	var numberOfCycles = Math.floor(shiftedRd / 1029983);
14747 	var shiftedDayInCycle = MathUtils.mod(shiftedRd, 1029983);
14748 	var yearInCycle = (shiftedDayInCycle === 1029982) ? 2820 : Math.floor((2816 * shiftedDayInCycle + 1031337) / 1028522);
14749 	var year = 474 + 2820 * numberOfCycles + yearInCycle;
14750 	return (year > 0) ? year : year - 1;
14751 };
14752 
14753 /**
14754  * @private
14755  * Calculate date components for the given RD date.
14756  */
14757 PersianAlgoDate.prototype._calcDateComponents = function () {
14758 	var remainder,
14759 		rd = this.rd.getRataDie();
14760 	
14761 	this.year = this._calcYear(rd);
14762 	
14763 	if (typeof(this.offset) === "undefined") {
14764 		// now offset the RD by the time zone, then recalculate in case we were 
14765 		// near the year boundary
14766 		if (!this.tz) {
14767 			this.tz = new TimeZone({id: this.timezone});
14768 		}
14769 		this.offset = this.tz.getOffsetMillis(this) / 86400000;
14770 	}
14771 	
14772 	if (this.offset !== 0) {
14773 		rd += this.offset;
14774 		this.year = this._calcYear(rd);
14775 	}
14776 	
14777 	//console.log("PersAlgoDate.calcComponent: calculating for rd " + rd);
14778 	//console.log("PersAlgoDate.calcComponent: year is " + ret.year);
14779 	var yearStart = this.newRd({
14780 		year: this.year,
14781 		month: 1,
14782 		day: 1,
14783 		hour: 0,
14784 		minute: 0,
14785 		second: 0,
14786 		millisecond: 0
14787 	});
14788 	remainder = rd - yearStart.getRataDie() + 1;
14789 	
14790 	this.dayOfYear = remainder;
14791 	
14792 	//console.log("PersAlgoDate.calcComponent: remainder is " + remainder);
14793 	
14794 	this.month = SearchUtils.bsearch(remainder, PersAlgoRataDie.cumMonthLengths);
14795 	remainder -= PersAlgoRataDie.cumMonthLengths[this.month-1];
14796 	
14797 	//console.log("PersAlgoDate.calcComponent: month is " + this.month + " and remainder is " + remainder);
14798 	
14799 	this.day = Math.floor(remainder);
14800 	remainder -= this.day;
14801 	
14802 	//console.log("PersAlgoDate.calcComponent: day is " + this.day + " and remainder is " + remainder);
14803 	
14804 	// now convert to milliseconds for the rest of the calculation
14805 	remainder = Math.round(remainder * 86400000);
14806 	
14807 	this.hour = Math.floor(remainder/3600000);
14808 	remainder -= this.hour * 3600000;
14809 	
14810 	this.minute = Math.floor(remainder/60000);
14811 	remainder -= this.minute * 60000;
14812 	
14813 	this.second = Math.floor(remainder/1000);
14814 	remainder -= this.second * 1000;
14815 	
14816 	this.millisecond = remainder;
14817 };
14818 
14819 /**
14820  * Return the day of the week of this date. The day of the week is encoded
14821  * as number from 0 to 6, with 0=Sunday, 1=Monday, etc., until 6=Saturday.
14822  * 
14823  * @return {number} the day of the week
14824  */
14825 PersianAlgoDate.prototype.getDayOfWeek = function() {
14826 	var rd = Math.floor(this.getRataDie());
14827 	return MathUtils.mod(rd-3, 7);
14828 };
14829 
14830 /**
14831  * Return the ordinal day of the year. Days are counted from 1 and proceed linearly up to 
14832  * 365, regardless of months or weeks, etc. That is, Farvardin 1st is day 1, and 
14833  * December 31st is 365 in regular years, or 366 in leap years.
14834  * @return {number} the ordinal day of the year
14835  */
14836 PersianAlgoDate.prototype.getDayOfYear = function() {
14837 	return PersAlgoRataDie.cumMonthLengths[this.month-1] + this.day;
14838 };
14839 
14840 /**
14841  * Return the era for this date as a number. The value for the era for Persian 
14842  * calendars is -1 for "before the persian era" (BP) and 1 for "the persian era" (anno 
14843  * persico or AP). 
14844  * BP dates are any date before Farvardin 1, 1 AP. In the proleptic Persian calendar, 
14845  * there is a year 0, so any years that are negative or zero are BP.
14846  * @return {number} 1 if this date is in the common era, -1 if it is before the 
14847  * common era 
14848  */
14849 PersianAlgoDate.prototype.getEra = function() {
14850 	return (this.year < 1) ? -1 : 1;
14851 };
14852 
14853 /**
14854  * Return the name of the calendar that governs this date.
14855  * 
14856  * @return {string} a string giving the name of the calendar
14857  */
14858 PersianAlgoDate.prototype.getCalendar = function() {
14859 	return "persian-algo";
14860 };
14861 
14862 // register with the factory method
14863 IDate._constructors["persian-algo"] = PersianAlgoDate;
14864 
14865 
14866 /*< HanCal.js */
14867 /*
14868  * han.js - Represent a Han Chinese Lunar calendar object.
14869  * 
14870  * Copyright © 2014-2015, JEDLSoft
14871  *
14872  * Licensed under the Apache License, Version 2.0 (the "License");
14873  * you may not use this file except in compliance with the License.
14874  * You may obtain a copy of the License at
14875  *
14876  *     http://www.apache.org/licenses/LICENSE-2.0
14877  *
14878  * Unless required by applicable law or agreed to in writing, software
14879  * distributed under the License is distributed on an "AS IS" BASIS,
14880  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14881  *
14882  * See the License for the specific language governing permissions and
14883  * limitations under the License.
14884  */
14885 
14886 /* !depends 
14887 ilib.js 
14888 Calendar.js 
14889 MathUtils.js 
14890 Astro.js
14891 GregorianDate.js
14892 GregRataDie.js
14893 RataDie.js
14894 */
14895 
14896 
14897 
14898 
14899 /**
14900  * @class
14901  * Construct a new Han algorithmic calendar object. This class encodes information about
14902  * a Han algorithmic calendar.<p>
14903  * 
14904  * 
14905  * @constructor
14906  * @param {Object=} params optional parameters to load the calendrical data
14907  * @extends Calendar
14908  */
14909 var HanCal = function(params) {
14910 	this.type = "han";
14911 	var sync = params && typeof(params.sync) === 'boolean' ? params.sync : true;
14912 	
14913 	Astro.initAstro(sync, params && params.loadParams, ilib.bind(this, function (x) {
14914 		if (params && typeof(params.callback) === 'function') {
14915 			params.callback(this);
14916 		}
14917 	}));
14918 };
14919 
14920 /**
14921  * @protected
14922  * @static
14923  * @param {number} year
14924  * @param {number=} cycle
14925  * @return {number}
14926  */
14927 HanCal._getElapsedYear = function(year, cycle) {
14928 	var elapsedYear = year || 0;
14929 	if (typeof(year) !== 'undefined' && year < 61 && typeof(cycle) !== 'undefined') {
14930 		elapsedYear = 60 * cycle + year;
14931 	}
14932 	return elapsedYear;
14933 };
14934 
14935 /**
14936  * @protected
14937  * @static
14938  * @param {number} jd julian day to calculate from
14939  * @param {number} longitude longitude to seek 
14940  * @returns {number} the julian day of the next time that the solar longitude 
14941  * is a multiple of the given longitude
14942  */
14943 HanCal._hanNextSolarLongitude = function(jd, longitude) {
14944 	var tz = HanCal._chineseTZ(jd);
14945 	var uni = Astro._universalFromLocal(jd, tz);
14946 	var sol = Astro._nextSolarLongitude(uni, longitude);
14947 	return Astro._localFromUniversal(sol, tz);
14948 };
14949 
14950 /**
14951  * @protected
14952  * @static
14953  * @param {number} jd julian day to calculate from 
14954  * @returns {number} the major solar term for the julian day
14955  */
14956 HanCal._majorSTOnOrAfter = function(jd) {
14957 	var tz = HanCal._chineseTZ(jd);
14958 	var uni = Astro._universalFromLocal(jd, tz);
14959 	var next = Astro._fixangle(30 * Math.ceil(Astro._solarLongitude(uni)/30));
14960 	return HanCal._hanNextSolarLongitude(jd, next);
14961 };
14962 
14963 /**
14964  * @protected
14965  * @static
14966  * @param {number} year the year for which the leap year information is being sought
14967  * @param {number=} cycle if the given year < 60, this can specify the cycle. If the
14968  * cycle is not given, then the year should be given as elapsed years since the beginning
14969  * of the epoch
14970  */
14971 HanCal._solsticeBefore = function (year, cycle) {
14972 	var elapsedYear = HanCal._getElapsedYear(year, cycle);
14973 	var gregyear = elapsedYear - 2697;
14974 	var rd = new GregRataDie({
14975 		year: gregyear-1, 
14976 		month: 12, 
14977 		day: 15, 
14978 		hour: 0, 
14979 		minute: 0, 
14980 		second: 0, 
14981 		millisecond: 0
14982 	});
14983 	return HanCal._majorSTOnOrAfter(rd.getRataDie() + RataDie.gregorianEpoch);
14984 };
14985 
14986 /**
14987  * @protected
14988  * @static
14989  * @param {number} jd julian day to calculate from
14990  * @returns {number} the current major solar term
14991  */
14992 HanCal._chineseTZ = function(jd) {
14993 	var year = GregorianDate._calcYear(jd - RataDie.gregorianEpoch);
14994 	return year < 1929 ? 465.6666666666666666 : 480;
14995 };
14996 
14997 /**
14998  * @protected
14999  * @static
15000  * @param {number} jd julian day to calculate from 
15001  * @returns {number} the julian day of next new moon on or after the given julian day date
15002  */
15003 HanCal._newMoonOnOrAfter = function(jd) {
15004 	var tz = HanCal._chineseTZ(jd);
15005 	var uni = Astro._universalFromLocal(jd, tz);
15006 	var moon = Astro._newMoonAtOrAfter(uni);
15007 	// floor to the start of the julian day
15008 	return Astro._floorToJD(Astro._localFromUniversal(moon, tz)); 
15009 };
15010 
15011 /**
15012  * @protected
15013  * @static
15014  * @param {number} jd julian day to calculate from 
15015  * @returns {number} the julian day of previous new moon before the given julian day date
15016  */
15017 HanCal._newMoonBefore = function(jd) {
15018 	var tz = HanCal._chineseTZ(jd);
15019 	var uni = Astro._universalFromLocal(jd, tz);
15020 	var moon = Astro._newMoonBefore(uni);
15021 	// floor to the start of the julian day
15022 	return Astro._floorToJD(Astro._localFromUniversal(moon, tz));
15023 };
15024 
15025 /**
15026  * @static
15027  * @protected
15028  * @param {number} year the year for which the leap year information is being sought
15029  * @param {number=} cycle if the given year < 60, this can specify the cycle. If the
15030  * cycle is not given, then the year should be given as elapsed years since the beginning
15031  * of the epoch
15032  */
15033 HanCal._leapYearCalc = function(year, cycle) {
15034 	var ret = {
15035 		elapsedYear: HanCal._getElapsedYear(year, cycle)
15036 	};
15037 	ret.solstice1 = HanCal._solsticeBefore(ret.elapsedYear);
15038 	ret.solstice2 = HanCal._solsticeBefore(ret.elapsedYear+1);
15039 	// ceil to the end of the julian day
15040 	ret.m1 = HanCal._newMoonOnOrAfter(Astro._ceilToJD(ret.solstice1));
15041 	ret.m2 = HanCal._newMoonBefore(Astro._ceilToJD(ret.solstice2));
15042 	
15043 	return ret;
15044 };
15045 
15046 /**
15047  * @protected
15048  * @static
15049  * @param {number} jd julian day to calculate from
15050  * @returns {number} the current major solar term
15051  */
15052 HanCal._currentMajorST = function(jd) {
15053 	var s = Astro._solarLongitude(Astro._universalFromLocal(jd, HanCal._chineseTZ(jd)));
15054 	return MathUtils.amod(2 + Math.floor(s/30), 12);
15055 };
15056 
15057 /**
15058  * @protected
15059  * @static
15060  * @param {number} jd julian day to calculate from
15061  * @returns {boolean} true if there is no major solar term in the same year
15062  */
15063 HanCal._noMajorST = function(jd) {
15064 	return HanCal._currentMajorST(jd) === HanCal._currentMajorST(HanCal._newMoonOnOrAfter(jd+1));
15065 };
15066 
15067 /**
15068  * Return the number of months in the given year. The number of months in a year varies
15069  * for some luni-solar calendars because in some years, an extra month is needed to extend the 
15070  * days in a year to an entire solar year. The month is represented as a 1-based number
15071  * where 1=first month, 2=second month, etc.
15072  * 
15073  * @param {number} year a year for which the number of months is sought
15074  * @param {number=} cycle if the given year < 60, this can specify the cycle. If the
15075  * cycle is not given, then the year should be given as elapsed years since the beginning
15076  * of the epoch
15077  * @return {number} The number of months in the given year
15078  */
15079 HanCal.prototype.getNumMonths = function(year, cycle) {
15080 	return this.isLeapYear(year, cycle) ? 13 : 12;
15081 };
15082 
15083 /**
15084  * Return the number of days in a particular month in a particular year. This function
15085  * can return a different number for a month depending on the year because of things
15086  * like leap years.
15087  * 
15088  * @param {number} month the elapsed month for which the length is sought
15089  * @param {number} year the elapsed year within which that month can be found
15090  * @return {number} the number of days within the given month in the given year
15091  */
15092 HanCal.prototype.getMonLength = function(month, year) {
15093 	// distance between two new moons in Nanjing China
15094 	var calc = HanCal._leapYearCalc(year);
15095 	var priorNewMoon = HanCal._newMoonOnOrAfter(calc.m1 + month * 29);
15096 	var postNewMoon = HanCal._newMoonOnOrAfter(priorNewMoon + 1);
15097 	return postNewMoon - priorNewMoon;
15098 };
15099 
15100 /**
15101  * Return the equivalent year in the 2820 year cycle that begins on 
15102  * Far 1, 474. This particular cycle obeys the cycle-of-years formula 
15103  * whereas the others do not specifically. This cycle can be used as
15104  * a proxy for other years outside of the cycle by shifting them into 
15105  * the cycle.   
15106  * @param {number} year year to find the equivalent cycle year for
15107  * @returns {number} the equivalent cycle year
15108  */
15109 HanCal.prototype.equivalentCycleYear = function(year) {
15110 	var y = year - (year >= 0 ? 474 : 473);
15111 	return MathUtils.mod(y, 2820) + 474;
15112 };
15113 
15114 /**
15115  * Return true if the given year is a leap year in the Han calendar.
15116  * If the year is given as a year/cycle combination, then the year should be in the 
15117  * range [1,60] and the given cycle is the cycle in which the year is located. If 
15118  * the year is greater than 60, then
15119  * it represents the total number of years elapsed in the proleptic calendar since
15120  * the beginning of the Chinese epoch in on 15 Feb, -2636 (Gregorian). In this 
15121  * case, the cycle parameter is ignored.
15122  * 
15123  * @param {number} year the year for which the leap year information is being sought
15124  * @param {number=} cycle if the given year < 60, this can specify the cycle. If the
15125  * cycle is not given, then the year should be given as elapsed years since the beginning
15126  * of the epoch
15127  * @return {boolean} true if the given year is a leap year
15128  */
15129 HanCal.prototype.isLeapYear = function(year, cycle) {
15130 	var calc = HanCal._leapYearCalc(year, cycle);
15131 	return Math.round((calc.m2 - calc.m1) / 29.530588853000001) === 12;
15132 };
15133 
15134 /**
15135  * Return the month of the year that is the leap month. If the given year is
15136  * not a leap year, then this method will return -1.
15137  * 
15138  * @param {number} year the year for which the leap year information is being sought
15139  * @param {number=} cycle if the given year < 60, this can specify the cycle. If the
15140  * cycle is not given, then the year should be given as elapsed years since the beginning
15141  * of the epoch
15142  * @return {number} the number of the month that is doubled in this leap year, or -1
15143  * if this is not a leap year
15144  */
15145 HanCal.prototype.getLeapMonth = function(year, cycle) {
15146 	var calc = HanCal._leapYearCalc(year, cycle);
15147 	
15148 	if (Math.round((calc.m2 - calc.m1) / 29.530588853000001) != 12) {
15149 		return -1; // no leap month
15150 	}
15151 	
15152 	// search between rd1 and rd2 for the first month with no major solar term. That is our leap month.
15153 	var month = 0;
15154 	var m = HanCal._newMoonOnOrAfter(calc.m1+1);
15155 	while (!HanCal._noMajorST(m)) {
15156 		month++;
15157 		m = HanCal._newMoonOnOrAfter(m+1);
15158 	}
15159 	
15160 	// return the number of the month that is doubled
15161 	return month; 
15162 };
15163 
15164 /**
15165  * Return the date of Chinese New Years in the given calendar year.
15166  * 
15167  * @param {number} year the Chinese year for which the new year information is being sought
15168  * @param {number=} cycle if the given year < 60, this can specify the cycle. If the
15169  * cycle is not given, then the year should be given as elapsed years since the beginning
15170  * of the epoch
15171  * @return {number} the julian day of the beginning of the given year 
15172  */
15173 HanCal.prototype.newYears = function(year, cycle) {
15174 	var calc = HanCal._leapYearCalc(year, cycle);
15175 	var m2 = HanCal._newMoonOnOrAfter(calc.m1+1);
15176 	if (Math.round((calc.m2 - calc.m1) / 29.530588853000001) === 12 &&
15177 			(HanCal._noMajorST(calc.m1) || HanCal._noMajorST(m2)) ) {
15178 		return HanCal._newMoonOnOrAfter(m2+1);
15179 	}
15180 	return m2;
15181 };
15182 
15183 /**
15184  * Return the type of this calendar.
15185  * 
15186  * @return {string} the name of the type of this calendar 
15187  */
15188 HanCal.prototype.getType = function() {
15189 	return this.type;
15190 };
15191 
15192 /**
15193  * Return a date instance for this calendar type using the given
15194  * options.
15195  * @param {Object} options options controlling the construction of 
15196  * the date instance
15197  * @return {HanDate} a date appropriate for this calendar type
15198  * @deprecated Since 11.0.5. Use DateFactory({calendar: cal.getType(), ...}) instead
15199  */
15200 HanCal.prototype.newDateInstance = function (options) {
15201 		return new HanDate(options);
15202 };
15203 
15204 /* register this calendar for the factory method */
15205 Calendar._constructors["han"] = HanCal;
15206 
15207 
15208 /*< HanRataDie.js */
15209 /*
15210  * HanDate.js - Represent a date in the Han algorithmic calendar
15211  * 
15212  * Copyright © 2014-2015, JEDLSoft
15213  *
15214  * Licensed under the Apache License, Version 2.0 (the "License");
15215  * you may not use this file except in compliance with the License.
15216  * You may obtain a copy of the License at
15217  *
15218  *     http://www.apache.org/licenses/LICENSE-2.0
15219  *
15220  * Unless required by applicable law or agreed to in writing, software
15221  * distributed under the License is distributed on an "AS IS" BASIS,
15222  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15223  *
15224  * See the License for the specific language governing permissions and
15225  * limitations under the License.
15226  */
15227 
15228 /* !depends
15229 ilib.js
15230 HanCal.js
15231 MathUtils.js
15232 RataDie.js
15233 */
15234 
15235 
15236 /**
15237  * Construct a new Han RD date number object. The constructor parameters can 
15238  * contain any of the following properties:
15239  * 
15240  * <ul>
15241  * <li><i>unixtime<i> - sets the time of this instance according to the given 
15242  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970, Gregorian
15243  * 
15244  * <li><i>julianday</i> - sets the time of this instance according to the given
15245  * Julian Day instance or the Julian Day given as a float
15246  * 
15247  * <li><i>cycle</i> - any integer giving the number of 60-year cycle in which the date is located.
15248  * If the cycle is not given but the year is, it is assumed that the year parameter is a fictitious 
15249  * linear count of years since the beginning of the epoch, much like other calendars. This linear
15250  * count is never used. If both the cycle and year are given, the year is wrapped to the range 0 
15251  * to 60 and treated as if it were a year in the regular 60-year cycle.
15252  * 
15253  * <li><i>year</i> - any integer, including 0
15254  * 
15255  * <li><i>month</i> - 1 to 12, where 1 means Farvardin, 2 means Ordibehesht, etc.
15256  * 
15257  * <li><i>day</i> - 1 to 31
15258  * 
15259  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
15260  * is always done with an unambiguous 24 hour representation
15261  * 
15262  * <li><i>minute</i> - 0 to 59
15263  * 
15264  * <li><i>second</i> - 0 to 59
15265  * 
15266  * <li><i>millisecond</i> - 0 to 999
15267  * 
15268  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
15269  * </ul>
15270  *
15271  * If the constructor is called with another Han date instance instead of
15272  * a parameter block, the other instance acts as a parameter block and its
15273  * settings are copied into the current instance.<p>
15274  * 
15275  * If the constructor is called with no arguments at all or if none of the 
15276  * properties listed above are present, then the RD is calculate based on 
15277  * the current date at the time of instantiation. <p>
15278  * 
15279  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
15280  * specified in the params, it is assumed that they have the smallest possible
15281  * value in the range for the property (zero or one).<p>
15282  * 
15283  * 
15284  * @private
15285  * @class
15286  * @constructor
15287  * @extends RataDie
15288  * @param {Object=} params parameters that govern the settings and behaviour of this Han RD date
15289  */
15290 var HanRataDie = function(params) {
15291 	this.rd = NaN;
15292 	if (params && params.cal) {
15293 		this.cal = params.cal;
15294 		RataDie.call(this, params);
15295 		if (params && typeof(params.callback) === 'function') {
15296 			params.callback(this);
15297 		}
15298 	} else {
15299 		new HanCal({
15300 			sync: params && params.sync,
15301 			loadParams: params && params.loadParams,
15302 			callback: ilib.bind(this, function(c) {
15303 				this.cal = c;
15304 				RataDie.call(this, params);
15305 				if (params && typeof(params.callback) === 'function') {
15306 					params.callback(this);
15307 				}
15308 			})
15309 		});
15310 	}
15311 };
15312 
15313 HanRataDie.prototype = new RataDie();
15314 HanRataDie.prototype.parent = RataDie;
15315 HanRataDie.prototype.constructor = HanRataDie;
15316 
15317 /**
15318  * The difference between a zero Julian day and the first Han date
15319  * which is February 15, -2636 (Gregorian).
15320  * @private
15321  * @type number
15322  */
15323 HanRataDie.epoch = 758325.5;
15324 
15325 /**
15326  * Calculate the Rata Die (fixed day) number of the given date from the
15327  * date components.
15328  *
15329  * @protected
15330  * @param {Object} date the date components to calculate the RD from
15331  */
15332 HanRataDie.prototype._setDateComponents = function(date) {
15333 	var calc = HanCal._leapYearCalc(date.year, date.cycle);
15334 	var m2 = HanCal._newMoonOnOrAfter(calc.m1+1);
15335 	var newYears;
15336 	this.leapYear = (Math.round((calc.m2 - calc.m1) / 29.530588853000001) === 12);
15337 	if (this.leapYear && (HanCal._noMajorST(calc.m1) || HanCal._noMajorST(m2)) ) {
15338 		newYears = HanCal._newMoonOnOrAfter(m2+1);
15339 	} else {
15340 		newYears = m2;
15341 	}
15342 
15343 	var priorNewMoon = HanCal._newMoonOnOrAfter(calc.m1 + date.month * 29); // this is a julian day
15344 	this.priorLeapMonth = HanRataDie._priorLeapMonth(newYears, HanCal._newMoonBefore(priorNewMoon));
15345 	this.leapMonth = (this.leapYear && HanCal._noMajorST(priorNewMoon) && !this.priorLeapMonth);
15346 
15347 	var rdtime = (date.hour * 3600000 +
15348 		date.minute * 60000 +
15349 		date.second * 1000 +
15350 		date.millisecond) /
15351 		86400000;
15352 	
15353 	/*
15354 	console.log("getRataDie: converting " +  JSON.stringify(date) + " to an RD");
15355 	console.log("getRataDie: year is " +  date.year + " plus cycle " + date.cycle);
15356 	console.log("getRataDie: isLeapYear is " +  this.leapYear);
15357 	console.log("getRataDie: priorNewMoon is " +  priorNewMoon);
15358 	console.log("getRataDie: day in month is " +  date.day);
15359 	console.log("getRataDie: rdtime is " +  rdtime);
15360 	console.log("getRataDie: rd is " +  (priorNewMoon + date.day - 1 + rdtime));
15361 	*/
15362 	
15363 	this.rd = priorNewMoon + date.day - 1 + rdtime - RataDie.gregorianEpoch;
15364 };
15365 
15366 /**
15367  * Return the rd number of the particular day of the week on or before the 
15368  * given rd. eg. The Sunday on or before the given rd.
15369  * @private
15370  * @param {number} rd the rata die date of the reference date
15371  * @param {number} dayOfWeek the day of the week that is being sought relative 
15372  * to the current date
15373  * @return {number} the rd of the day of the week
15374  */
15375 HanRataDie.prototype._onOrBefore = function(rd, dayOfWeek) {
15376 	return rd - MathUtils.mod(Math.floor(rd) - dayOfWeek, 7);
15377 };
15378 
15379 /**
15380  * @protected
15381  * @static
15382  * @param {number} jd1 first julian day
15383  * @param {number} jd2 second julian day
15384  * @returns {boolean} true if there is a leap month earlier in the same year 
15385  * as the given months 
15386  */
15387 HanRataDie._priorLeapMonth = function(jd1, jd2) {
15388 	return jd2 >= jd1 &&
15389 		(HanRataDie._priorLeapMonth(jd1, HanCal._newMoonBefore(jd2)) ||
15390 				HanCal._noMajorST(jd2));
15391 };
15392 
15393 
15394 
15395 /*< HanDate.js */
15396 /*
15397  * HanDate.js - Represent a date in the Han algorithmic calendar
15398  * 
15399  * Copyright © 2014-2015, JEDLSoft
15400  *
15401  * Licensed under the Apache License, Version 2.0 (the "License");
15402  * you may not use this file except in compliance with the License.
15403  * You may obtain a copy of the License at
15404  *
15405  *     http://www.apache.org/licenses/LICENSE-2.0
15406  *
15407  * Unless required by applicable law or agreed to in writing, software
15408  * distributed under the License is distributed on an "AS IS" BASIS,
15409  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15410  *
15411  * See the License for the specific language governing permissions and
15412  * limitations under the License.
15413  */
15414 
15415 /* !depends
15416 ilib.js
15417 IDate.js
15418 GregorianDate.js 
15419 HanCal.js
15420 Astro.js 
15421 JSUtils.js
15422 MathUtils.js
15423 LocaleInfo.js 
15424 Locale.js
15425 TimeZone.js
15426 HanRataDie.js
15427 RataDie.js
15428 */
15429 
15430 
15431 
15432 
15433 /**
15434  * @class
15435  * 
15436  * Construct a new Han date object. The constructor parameters can 
15437  * contain any of the following properties:
15438  * 
15439  * <ul>
15440  * <li><i>unixtime<i> - sets the time of this instance according to the given 
15441  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970, Gregorian
15442  * 
15443  * <li><i>julianday</i> - sets the time of this instance according to the given
15444  * Julian Day instance or the Julian Day given as a float
15445  * 
15446  * <li><i>cycle</i> - any integer giving the number of 60-year cycle in which the date is located.
15447  * If the cycle is not given but the year is, it is assumed that the year parameter is a fictitious 
15448  * linear count of years since the beginning of the epoch, much like other calendars. This linear
15449  * count is never used. If both the cycle and year are given, the year is wrapped to the range 0 
15450  * to 60 and treated as if it were a year in the regular 60-year cycle.
15451  * 
15452  * <li><i>year</i> - any integer, including 0
15453  * 
15454  * <li><i>month</i> - 1 to 12, where 1 means Farvardin, 2 means Ordibehesht, etc.
15455  * 
15456  * <li><i>day</i> - 1 to 31
15457  * 
15458  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
15459  * is always done with an unambiguous 24 hour representation
15460  * 
15461  * <li><i>minute</i> - 0 to 59
15462  * 
15463  * <li><i>second</i> - 0 to 59
15464  * 
15465  * <li><i>millisecond</i> - 0 to 999
15466  * 
15467  * <li><i>timezone</i> - the TimeZone instance or time zone name as a string 
15468  * of this han date. The date/time is kept in the local time. The time zone
15469  * is used later if this date is formatted according to a different time zone and
15470  * the difference has to be calculated, or when the date format has a time zone
15471  * component in it.
15472  * 
15473  * <li><i>locale</i> - locale for this han date. If the time zone is not 
15474  * given, it can be inferred from this locale. For locales that span multiple
15475  * time zones, the one with the largest population is chosen as the one that 
15476  * represents the locale.
15477  * 
15478  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
15479  * </ul>
15480  *
15481  * If the constructor is called with another Han date instance instead of
15482  * a parameter block, the other instance acts as a parameter block and its
15483  * settings are copied into the current instance.<p>
15484  * 
15485  * If the constructor is called with no arguments at all or if none of the 
15486  * properties listed above 
15487  * from <i>unixtime</i> through <i>millisecond</i> are present, then the date 
15488  * components are 
15489  * filled in with the current date at the time of instantiation. Note that if
15490  * you do not give the time zone when defaulting to the current time and the 
15491  * time zone for all of ilib was not set with <i>ilib.setTimeZone()</i>, then the
15492  * time zone will default to UTC ("Universal Time, Coordinated" or "Greenwich 
15493  * Mean Time").<p>
15494  * 
15495  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
15496  * specified in the params, it is assumed that they have the smallest possible
15497  * value in the range for the property (zero or one).<p>
15498  * 
15499  * 
15500  * @constructor
15501  * @extends Date
15502  * @param {Object=} params parameters that govern the settings and behaviour of this Han date
15503  */
15504 var HanDate = function(params) {
15505 	this.timezone = "local";
15506 	if (params) {
15507 		if (params.locale) {
15508 			this.locale = (typeof(params.locale) === 'string') ? new Locale(params.locale) : params.locale;
15509 			var li = new LocaleInfo(this.locale);
15510 			this.timezone = li.getTimeZone(); 
15511 		}
15512 		if (params.timezone) {
15513 			this.timezone = params.timezone;
15514 		}
15515 	}
15516 	
15517 	new HanCal({
15518 		sync: params && typeof(params) === 'boolean' ? params.sync : true,
15519 		loadParams: params && params.loadParams,
15520 		callback: ilib.bind(this, function (cal) {
15521 			this.cal = cal;
15522 	
15523 			if (params && (params.year || params.month || params.day || params.hour ||
15524 				params.minute || params.second || params.millisecond || params.cycle || params.cycleYear)) {
15525 				if (typeof(params.cycle) !== 'undefined') {
15526 					/**
15527 					 * Cycle number in the Han calendar.
15528 					 * @type number
15529 					 */
15530 					this.cycle = parseInt(params.cycle, 10) || 0;
15531 					
15532 					var year = (typeof(params.year) !== 'undefined' ? parseInt(params.year, 10) : parseInt(params.cycleYear, 10)) || 0;
15533 					
15534 					/**
15535 					 * Year in the Han calendar.
15536 					 * @type number
15537 					 */
15538 					this.year = HanCal._getElapsedYear(year, this.cycle);
15539 				} else {
15540 					if (typeof(params.year) !== 'undefined') {
15541 						this.year = parseInt(params.year, 10) || 0;
15542 						this.cycle = Math.floor((this.year - 1) / 60);
15543 					} else {
15544 						this.year = this.cycle = 0;
15545 					}
15546 				}	
15547 				
15548 				/**
15549 				 * The month number, ranging from 1 to 13
15550 				 * @type number
15551 				 */
15552 				this.month = parseInt(params.month, 10) || 1;
15553 	
15554 				/**
15555 				 * The day of the month. This ranges from 1 to 30.
15556 				 * @type number
15557 				 */
15558 				this.day = parseInt(params.day, 10) || 1;
15559 				
15560 				/**
15561 				 * The hour of the day. This can be a number from 0 to 23, as times are
15562 				 * stored unambiguously in the 24-hour clock.
15563 				 * @type number
15564 				 */
15565 				this.hour = parseInt(params.hour, 10) || 0;
15566 	
15567 				/**
15568 				 * The minute of the hours. Ranges from 0 to 59.
15569 				 * @type number
15570 				 */
15571 				this.minute = parseInt(params.minute, 10) || 0;
15572 	
15573 				/**
15574 				 * The second of the minute. Ranges from 0 to 59.
15575 				 * @type number
15576 				 */
15577 				this.second = parseInt(params.second, 10) || 0;
15578 	
15579 				/**
15580 				 * The millisecond of the second. Ranges from 0 to 999.
15581 				 * @type number
15582 				 */
15583 				this.millisecond = parseInt(params.millisecond, 10) || 0;
15584 			
15585 				// derived properties
15586 				
15587 				/**
15588 				 * Year in the cycle of the Han calendar
15589 				 * @type number
15590 				 */
15591 				this.cycleYear = MathUtils.amod(this.year, 60); 
15592 
15593 				/**
15594 				 * The day of the year. Ranges from 1 to 384.
15595 				 * @type number
15596 				 */
15597 				this.dayOfYear = parseInt(params.dayOfYear, 10);
15598 	
15599 				if (typeof(params.dst) === 'boolean') {
15600 					this.dst = params.dst;
15601 				}
15602 				
15603 				this.newRd({
15604 					cal: this.cal,
15605 					cycle: this.cycle,
15606 					year: this.year,
15607 					month: this.month,
15608 					day: this.day,
15609 					hour: this.hour,
15610 					minute: this.minute,
15611 					second: this.second,
15612 					millisecond: this.millisecond,
15613 					sync: params && typeof(params.sync) === 'boolean' ? params.sync : true,
15614 					loadParams: params && params.loadParams,
15615 					callback: ilib.bind(this, function (rd) {
15616 						if (rd) {
15617 							this.rd = rd;
15618 							
15619 							// add the time zone offset to the rd to convert to UTC
15620 							if (!this.tz) {
15621 								this.tz = new TimeZone({id: this.timezone});
15622 							}
15623 							// getOffsetMillis requires that this.year, this.rd, and this.dst 
15624 							// are set in order to figure out which time zone rules apply and 
15625 							// what the offset is at that point in the year
15626 							this.offset = this.tz._getOffsetMillisWallTime(this) / 86400000;
15627 							if (this.offset !== 0) {
15628 								this.rd = this.newRd({
15629 									cal: this.cal,
15630 									rd: this.rd.getRataDie() - this.offset
15631 								});
15632 								this._calcLeap();
15633 							} else {
15634 								// re-use the derived properties from the RD calculations
15635 								this.leapMonth = this.rd.leapMonth;
15636 								this.priorLeapMonth = this.rd.priorLeapMonth;
15637 								this.leapYear = this.rd.leapYear;
15638 							}
15639 						}
15640 						
15641 						if (!this.rd) {
15642 							this.rd = this.newRd(JSUtils.merge(params || {}, {
15643 								cal: this.cal
15644 							}));
15645 							this._calcDateComponents();
15646 						}
15647 						
15648 						if (params && typeof(params.onLoad) === 'function') {
15649 							params.onLoad(this);
15650 						}
15651 					})
15652 				});
15653 			} else {
15654 				if (!this.rd) {
15655 					this.rd = this.newRd(JSUtils.merge(params || {}, {
15656 						cal: this.cal
15657 					}));
15658 					this._calcDateComponents();
15659 				}
15660 				
15661 				if (params && typeof(params.onLoad) === 'function') {
15662 					params.onLoad(this);
15663 				}
15664 			}
15665 		})
15666 	});
15667 
15668 };
15669 
15670 HanDate.prototype = new IDate({noinstance: true});
15671 HanDate.prototype.parent = IDate;
15672 HanDate.prototype.constructor = HanDate;
15673 
15674 /**
15675  * Return a new RD for this date type using the given params.
15676  * @protected
15677  * @param {Object=} params the parameters used to create this rata die instance
15678  * @returns {RataDie} the new RD instance for the given params
15679  */
15680 HanDate.prototype.newRd = function (params) {
15681 	return new HanRataDie(params);
15682 };
15683 
15684 /**
15685  * Return the year for the given RD
15686  * @protected
15687  * @param {number} rd RD to calculate from 
15688  * @returns {number} the year for the RD
15689  */
15690 HanDate.prototype._calcYear = function(rd) {
15691 	var gregdate = new GregorianDate({
15692 		rd: rd,
15693 		timezone: this.timezone
15694 	});
15695 	var hanyear = gregdate.year + 2697;
15696 	var newYears = this.cal.newYears(hanyear);
15697 	return hanyear - ((rd + RataDie.gregorianEpoch < newYears) ? 1 : 0);
15698 };
15699 
15700 /** 
15701  * @private 
15702  * Calculate the leap year and months from the RD.
15703  */
15704 HanDate.prototype._calcLeap = function() {
15705 	var jd = this.rd.getRataDie() + RataDie.gregorianEpoch;
15706 	
15707 	var calc = HanCal._leapYearCalc(this.year);
15708 	var m2 = HanCal._newMoonOnOrAfter(calc.m1+1);
15709 	this.leapYear = Math.round((calc.m2 - calc.m1) / 29.530588853000001) === 12;
15710 	
15711 	var newYears = (this.leapYear &&
15712 		(HanCal._noMajorST(calc.m1) || HanCal._noMajorST(m2))) ?
15713 				HanCal._newMoonOnOrAfter(m2+1) : m2;
15714 	
15715 	var m = HanCal._newMoonBefore(jd + 1);
15716 	this.priorLeapMonth = HanRataDie._priorLeapMonth(newYears, HanCal._newMoonBefore(m));
15717 	this.leapMonth = (this.leapYear && HanCal._noMajorST(m) && !this.priorLeapMonth);
15718 };
15719 
15720 /**
15721  * @private
15722  * Calculate date components for the given RD date.
15723  */
15724 HanDate.prototype._calcDateComponents = function () {
15725 	var remainder,
15726 		jd = this.rd.getRataDie() + RataDie.gregorianEpoch;
15727 
15728 	// console.log("HanDate._calcDateComponents: calculating for jd " + jd);
15729 
15730 	if (typeof(this.offset) === "undefined") {
15731 		// now offset the jd by the time zone, then recalculate in case we were 
15732 		// near the year boundary
15733 		if (!this.tz) {
15734 			this.tz = new TimeZone({id: this.timezone});
15735 		}
15736 		this.offset = this.tz.getOffsetMillis(this) / 86400000;
15737 	}
15738 	
15739 	if (this.offset !== 0) {
15740 		jd += this.offset;
15741 	}
15742 
15743 	// use the Gregorian calendar objects as a convenient way to short-cut some
15744 	// of the date calculations
15745 	
15746 	var gregyear = GregorianDate._calcYear(this.rd.getRataDie());
15747 	this.year = gregyear + 2697;
15748 	var calc = HanCal._leapYearCalc(this.year);
15749 	var m2 = HanCal._newMoonOnOrAfter(calc.m1+1);
15750 	this.leapYear = Math.round((calc.m2 - calc.m1) / 29.530588853000001) === 12;
15751 	var newYears = (this.leapYear &&
15752 		(HanCal._noMajorST(calc.m1) || HanCal._noMajorST(m2))) ?
15753 				HanCal._newMoonOnOrAfter(m2+1) : m2;
15754 	
15755 	// See if it's between Jan 1 and the Chinese new years of that Gregorian year. If
15756 	// so, then the Han year is actually the previous one
15757 	if (jd < newYears) {
15758 		this.year--;
15759 		calc = HanCal._leapYearCalc(this.year);
15760 		m2 = HanCal._newMoonOnOrAfter(calc.m1+1);
15761 		this.leapYear = Math.round((calc.m2 - calc.m1) / 29.530588853000001) === 12;
15762 		newYears = (this.leapYear &&
15763 			(HanCal._noMajorST(calc.m1) || HanCal._noMajorST(m2))) ?
15764 					HanCal._newMoonOnOrAfter(m2+1) : m2;
15765 	}
15766 	// month is elapsed month, not the month number + leap month boolean
15767 	var m = HanCal._newMoonBefore(jd + 1);
15768 	this.month = Math.round((m - calc.m1) / 29.530588853000001);
15769 	
15770 	this.priorLeapMonth = HanRataDie._priorLeapMonth(newYears, HanCal._newMoonBefore(m));
15771 	this.leapMonth = (this.leapYear && HanCal._noMajorST(m) && !this.priorLeapMonth);
15772 	
15773 	this.cycle = Math.floor((this.year - 1) / 60);
15774 	this.cycleYear = MathUtils.amod(this.year, 60);
15775 	this.day = Astro._floorToJD(jd) - m + 1;
15776 
15777 	/*
15778 	console.log("HanDate._calcDateComponents: year is " + this.year);
15779 	console.log("HanDate._calcDateComponents: isLeapYear is " + this.leapYear);
15780 	console.log("HanDate._calcDateComponents: cycle is " + this.cycle);
15781 	console.log("HanDate._calcDateComponents: cycleYear is " + this.cycleYear);
15782 	console.log("HanDate._calcDateComponents: month is " + this.month);
15783 	console.log("HanDate._calcDateComponents: isLeapMonth is " + this.leapMonth);
15784 	console.log("HanDate._calcDateComponents: day is " + this.day);
15785 	*/
15786 
15787 	// floor to the start of the julian day
15788 	remainder = jd - Astro._floorToJD(jd);
15789 	
15790 	// console.log("HanDate._calcDateComponents: time remainder is " + remainder);
15791 	
15792 	// now convert to milliseconds for the rest of the calculation
15793 	remainder = Math.round(remainder * 86400000);
15794 	
15795 	this.hour = Math.floor(remainder/3600000);
15796 	remainder -= this.hour * 3600000;
15797 	
15798 	this.minute = Math.floor(remainder/60000);
15799 	remainder -= this.minute * 60000;
15800 	
15801 	this.second = Math.floor(remainder/1000);
15802 	remainder -= this.second * 1000;
15803 	
15804 	this.millisecond = remainder;
15805 };
15806 
15807 /**
15808  * Return the year within the Chinese cycle of this date. Cycles are 60 
15809  * years long, and the value returned from this method is the number of the year 
15810  * within this cycle. The year returned from getYear() is the total elapsed 
15811  * years since the beginning of the Chinese epoch and does not include 
15812  * the cycles. 
15813  * 
15814  * @return {number} the year within the current Chinese cycle
15815  */
15816 HanDate.prototype.getCycleYears = function() {
15817 	return this.cycleYear;
15818 };
15819 
15820 /**
15821  * Return the Chinese cycle number of this date. Cycles are 60 years long,
15822  * and the value returned from getCycleYear() is the number of the year 
15823  * within this cycle. The year returned from getYear() is the total elapsed 
15824  * years since the beginning of the Chinese epoch and does not include 
15825  * the cycles. 
15826  * 
15827  * @return {number} the current Chinese cycle
15828  */
15829 HanDate.prototype.getCycles = function() {
15830 	return this.cycle;
15831 };
15832 
15833 /**
15834  * Return whether the year of this date is a leap year in the Chinese Han 
15835  * calendar. 
15836  * 
15837  * @return {boolean} true if the year of this date is a leap year in the 
15838  * Chinese Han calendar. 
15839  */
15840 HanDate.prototype.isLeapYear = function() {
15841 	return this.leapYear;
15842 };
15843 
15844 /**
15845  * Return whether the month of this date is a leap month in the Chinese Han 
15846  * calendar.
15847  * 
15848  * @return {boolean} true if the month of this date is a leap month in the 
15849  * Chinese Han calendar.
15850  */
15851 HanDate.prototype.isLeapMonth = function() {
15852 	return this.leapMonth;
15853 };
15854 
15855 /**
15856  * Return the day of the week of this date. The day of the week is encoded
15857  * as number from 0 to 6, with 0=Sunday, 1=Monday, etc., until 6=Saturday.
15858  * 
15859  * @return {number} the day of the week
15860  */
15861 HanDate.prototype.getDayOfWeek = function() {
15862 	var rd = Math.floor(this.rd.getRataDie() + (this.offset || 0));
15863 	return MathUtils.mod(rd, 7);
15864 };
15865 
15866 /**
15867  * Return the ordinal day of the year. Days are counted from 1 and proceed linearly up to 
15868  * 365, regardless of months or weeks, etc. That is, Farvardin 1st is day 1, and 
15869  * December 31st is 365 in regular years, or 366 in leap years.
15870  * @return {number} the ordinal day of the year
15871  */
15872 HanDate.prototype.getDayOfYear = function() {
15873 	var newYears = this.cal.newYears(this.year);
15874 	var priorNewMoon = HanCal._newMoonOnOrAfter(newYears + (this.month -1) * 29);
15875 	return priorNewMoon - newYears + this.day;
15876 };
15877 
15878 /**
15879  * Return the era for this date as a number. The value for the era for Han 
15880  * calendars is -1 for "before the han era" (BP) and 1 for "the han era" (anno 
15881  * persico or AP). 
15882  * BP dates are any date before Farvardin 1, 1 AP. In the proleptic Han calendar, 
15883  * there is a year 0, so any years that are negative or zero are BP.
15884  * @return {number} 1 if this date is in the common era, -1 if it is before the 
15885  * common era 
15886  */
15887 HanDate.prototype.getEra = function() {
15888 	return (this.year < 1) ? -1 : 1;
15889 };
15890 
15891 /**
15892  * Return the name of the calendar that governs this date.
15893  * 
15894  * @return {string} a string giving the name of the calendar
15895  */
15896 HanDate.prototype.getCalendar = function() {
15897 	return "han";
15898 };
15899 
15900 // register with the factory method
15901 IDate._constructors["han"] = HanDate;
15902 
15903 
15904 /*< EthiopicCal.js */
15905 /*
15906  * ethiopic.js - Represent a Ethiopic calendar object.
15907  * 
15908  * Copyright © 2015, JEDLSoft
15909  *
15910  * Licensed under the Apache License, Version 2.0 (the "License");
15911  * you may not use this file except in compliance with the License.
15912  * You may obtain a copy of the License at
15913  *
15914  *     http://www.apache.org/licenses/LICENSE-2.0
15915  *
15916  * Unless required by applicable law or agreed to in writing, software
15917  * distributed under the License is distributed on an "AS IS" BASIS,
15918  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15919  *
15920  * See the License for the specific language governing permissions and
15921  * limitations under the License.
15922  */
15923 
15924 /* !depends ilib.js Calendar.js Utils.js MathUtils.js */
15925 
15926 
15927 
15928 /**
15929  * @class
15930  * Construct a new Ethiopic calendar object. This class encodes information about
15931  * a Ethiopic calendar.<p>
15932  * 
15933  * 
15934  * @constructor
15935  * @extends Calendar
15936  */
15937 var EthiopicCal = function() {
15938 	this.type = "ethiopic";
15939 };
15940 
15941 /**
15942  * Return the number of months in the given year. The number of months in a year varies
15943  * for lunar calendars because in some years, an extra month is needed to extend the 
15944  * days in a year to an entire solar year. The month is represented as a 1-based number
15945  * where 1=Maskaram, 2=Teqemt, etc. until 13=Paguemen.
15946  * 
15947  * @param {number} year a year for which the number of months is sought
15948  */
15949 EthiopicCal.prototype.getNumMonths = function(year) {
15950 	return 13;
15951 };
15952 
15953 /**
15954  * Return the number of days in a particular month in a particular year. This function
15955  * can return a different number for a month depending on the year because of things
15956  * like leap years.
15957  * 
15958  * @param {number|string} month the month for which the length is sought
15959  * @param {number} year the year within which that month can be found
15960  * @return {number} the number of days within the given month in the given year
15961  */
15962 EthiopicCal.prototype.getMonLength = function(month, year) {
15963 	var m = month;
15964 	switch (typeof(m)) {
15965         case "string": 
15966             m = parseInt(m, 10); 
15967             break;
15968         case "function":
15969         case "object":
15970         case "undefined":
15971             return 30;
15972             break;
15973     }    
15974 	if (m < 13) {
15975 		return 30;
15976 	} else {
15977 		return this.isLeapYear(year) ? 6 : 5;
15978 	}
15979 };
15980 
15981 /**
15982  * Return true if the given year is a leap year in the Ethiopic calendar.
15983  * The year parameter may be given as a number, or as a JulDate object.
15984  * @param {number|EthiopicDate|string} year the year for which the leap year information is being sought
15985  * @return {boolean} true if the given year is a leap year
15986  */
15987 EthiopicCal.prototype.isLeapYear = function(year) {
15988 	var y = year;
15989 	 switch (typeof(y)) {
15990         case "string":
15991             y = parseInt(y, 10);
15992             break;
15993         case "object":
15994             if (typeof(y.year) !== "number") { // in case it is an ilib.Date object
15995                 return false;
15996             }
15997             y = y.year;
15998             break;
15999         case "function":
16000         case "undefined":
16001             return false;
16002             break;
16003     }
16004 	return MathUtils.mod(y, 4) === 3;
16005 };
16006 
16007 /**
16008  * Return the type of this calendar.
16009  * 
16010  * @return {string} the name of the type of this calendar 
16011  */
16012 EthiopicCal.prototype.getType = function() {
16013 	return this.type;
16014 };
16015 
16016 /**
16017  * Return a date instance for this calendar type using the given
16018  * options.
16019  * @param {Object} options options controlling the construction of 
16020  * the date instance
16021  * @return {IDate} a date appropriate for this calendar type
16022  * @deprecated Since 11.0.5. Use DateFactory({calendar: cal.getType(), ...}) instead
16023  */
16024 EthiopicCal.prototype.newDateInstance = function (options) {
16025 		return new EthiopicDate(options);
16026 };
16027 
16028 /* register this calendar for the factory method */
16029 Calendar._constructors["ethiopic"] = EthiopicCal;
16030 
16031 
16032 /*< EthiopicRataDie.js */
16033 /*
16034  * EthiopicRataDie.js - Represent an RD date in the Ethiopic calendar
16035  * 
16036  * Copyright © 2015, JEDLSoft
16037  *
16038  * Licensed under the Apache License, Version 2.0 (the "License");
16039  * you may not use this file except in compliance with the License.
16040  * You may obtain a copy of the License at
16041  *
16042  *     http://www.apache.org/licenses/LICENSE-2.0
16043  *
16044  * Unless required by applicable law or agreed to in writing, software
16045  * distributed under the License is distributed on an "AS IS" BASIS,
16046  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16047  *
16048  * See the License for the specific language governing permissions and
16049  * limitations under the License.
16050  */
16051 
16052 /* !depends 
16053 ilib.js
16054 EthiopicCal.js
16055 RataDie.js
16056 */
16057 
16058 
16059 /**
16060  * @class
16061  * Construct a new Ethiopic RD date number object. The constructor parameters can 
16062  * contain any of the following properties:
16063  * 
16064  * <ul>
16065  * <li><i>unixtime<i> - sets the time of this instance according to the given 
16066  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970.
16067  * 
16068  * <li><i>julianday</i> - sets the time of this instance according to the given
16069  * Julian Day instance or the Julian Day given as a float
16070  * 
16071  * <li><i>year</i> - any integer, including 0
16072  * 
16073  * <li><i>month</i> - 1 to 12, where 1 means Maskaram, 2 means Teqemt, etc., and 13 means Paguemen
16074  * 
16075  * <li><i>day</i> - 1 to 30
16076  * 
16077  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
16078  * is always done with an unambiguous 24 hour representation
16079  * 
16080  * <li><i>minute</i> - 0 to 59
16081  * 
16082  * <li><i>second</i> - 0 to 59
16083  * 
16084  * <li><i>millisecond</i> - 0 to 999
16085  * 
16086  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
16087  * </ul>
16088  *
16089  * If the constructor is called with another Ethiopic date instance instead of
16090  * a parameter block, the other instance acts as a parameter block and its
16091  * settings are copied into the current instance.<p>
16092  * 
16093  * If the constructor is called with no arguments at all or if none of the 
16094  * properties listed above are present, then the RD is calculate based on 
16095  * the current date at the time of instantiation. <p>
16096  * 
16097  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
16098  * specified in the params, it is assumed that they have the smallest possible
16099  * value in the range for the property (zero or one).<p>
16100  * 
16101  * 
16102  * @private
16103  * @constructor
16104  * @extends RataDie
16105  * @param {Object=} params parameters that govern the settings and behaviour of this Ethiopic RD date
16106  */
16107 var EthiopicRataDie = function(params) {
16108 	this.cal = params && params.cal || new EthiopicCal();
16109 	this.rd = NaN;
16110 	RataDie.call(this, params);
16111 };
16112 
16113 EthiopicRataDie.prototype = new RataDie();
16114 EthiopicRataDie.prototype.parent = RataDie;
16115 EthiopicRataDie.prototype.constructor = EthiopicRataDie;
16116 
16117 /**
16118  * The difference between the zero Julian day and the first Ethiopic date
16119  * of Friday, August 29, 8 CE Julian at 6:00am UTC.<p> 
16120  * 
16121  * See <a href="http://us.wow.com/wiki/Time_in_Ethiopia?s_chn=90&s_pt=aolsem&v_t=aolsem"
16122  * Time in Ethiopia</a> for information about how time is handled in Ethiopia.
16123  * 
16124  * @protected
16125  * @type number
16126  */
16127 EthiopicRataDie.prototype.epoch = 1724219.75;
16128 
16129 /**
16130  * Calculate the Rata Die (fixed day) number of the given date from the
16131  * date components.
16132  * 
16133  * @protected
16134  * @param {Object} date the date components to calculate the RD from
16135  */
16136 EthiopicRataDie.prototype._setDateComponents = function(date) {
16137 	var year = date.year;
16138 	var years = 365 * (year - 1) + Math.floor(year/4);
16139 	var dayInYear = (date.month-1) * 30 + date.day;
16140 	var rdtime = (date.hour * 3600000 +
16141 		date.minute * 60000 +
16142 		date.second * 1000 +
16143 		date.millisecond) / 
16144 		86400000;
16145 	
16146 	/*
16147 	console.log("calcRataDie: converting " +  JSON.stringify(parts));
16148 	console.log("getRataDie: year is " +  years);
16149 	console.log("getRataDie: day in year is " +  dayInYear);
16150 	console.log("getRataDie: rdtime is " +  rdtime);
16151 	console.log("getRataDie: rd is " +  (years + dayInYear + rdtime));
16152 	*/
16153 	
16154 	this.rd = years + dayInYear + rdtime;
16155 };
16156 
16157 
16158 
16159 /*< EthiopicDate.js */
16160 /*
16161  * EthiopicDate.js - Represent a date in the Ethiopic calendar
16162  * 
16163  * Copyright © 2015, JEDLSoft
16164  *
16165  * Licensed under the Apache License, Version 2.0 (the "License");
16166  * you may not use this file except in compliance with the License.
16167  * You may obtain a copy of the License at
16168  *
16169  *     http://www.apache.org/licenses/LICENSE-2.0
16170  *
16171  * Unless required by applicable law or agreed to in writing, software
16172  * distributed under the License is distributed on an "AS IS" BASIS,
16173  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16174  *
16175  * See the License for the specific language governing permissions and
16176  * limitations under the License.
16177  */
16178 
16179 /* !depends 
16180 ilib.js
16181 IDate.js 
16182 EthiopicCal.js 
16183 MathUtils.js
16184 Locale.js
16185 LocaleInfo.js 
16186 TimeZone.js
16187 EthiopicRataDie.js
16188 */
16189 
16190 
16191 
16192 /**
16193  * @class
16194  * Construct a new date object for the Ethiopic Calendar. The constructor can be called
16195  * with a parameter object that contains any of the following properties:
16196  * 
16197  * <ul>
16198  * <li><i>unixtime<i> - sets the time of this instance according to the given 
16199  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970 (Gregorian).
16200  * <li><i>julianday</i> - the Julian Day to set into this date
16201  * <li><i>year</i> - any integer
16202  * <li><i>month</i> - 1 to 13, where 1 means Maskaram, 2 means Teqemt, etc., and 13 means Paguemen
16203  * <li><i>day</i> - 1 to 30
16204  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
16205  * is always done with an unambiguous 24 hour representation
16206  * <li><i>minute</i> - 0 to 59
16207  * <li><i>second</i> - 0 to 59
16208  * <li><i>millisecond<i> - 0 to 999
16209  * <li><i>locale</i> - the TimeZone instance or time zone name as a string 
16210  * of this ethiopic date. The date/time is kept in the local time. The time zone
16211  * is used later if this date is formatted according to a different time zone and
16212  * the difference has to be calculated, or when the date format has a time zone
16213  * component in it.
16214  * <li><i>timezone</i> - the time zone of this instance. If the time zone is not 
16215  * given, it can be inferred from this locale. For locales that span multiple
16216  * time zones, the one with the largest population is chosen as the one that 
16217  * represents the locale. 
16218  * 
16219  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
16220  * </ul>
16221  *  
16222  * If called with another Ethiopic date argument, the date components of the given
16223  * date are copied into the current one.<p>
16224  * 
16225  * If the constructor is called with no arguments at all or if none of the 
16226  * properties listed above 
16227  * from <i>unixtime</i> through <i>millisecond</i> are present, then the date 
16228  * components are 
16229  * filled in with the current date at the time of instantiation. Note that if
16230  * you do not give the time zone when defaulting to the current time and the 
16231  * time zone for all of ilib was not set with <i>ilib.setTimeZone()</i>, then the
16232  * time zone will default to UTC ("Universal Time, Coordinated" or "Greenwich 
16233  * Mean Time").<p>
16234  * 
16235  * 
16236  * @constructor
16237  * @extends IDate
16238  * @param {Object=} params parameters that govern the settings and behaviour of this Ethiopic date
16239  */
16240 var EthiopicDate = function(params) {
16241 	this.cal = new EthiopicCal();
16242 	
16243 	if (params) {
16244 		if (typeof(params.noinstance) === 'boolean' && params.noinstance) {
16245 			// for doing inheritance, so don't need to fill in the data. The inheriting class only wants the methods.
16246 			return;
16247 		}
16248 		if (params.locale) {
16249 			this.locale = (typeof(params.locale) === 'string') ? new Locale(params.locale) : params.locale;
16250 			var li = new LocaleInfo(this.locale);
16251 			this.timezone = li.getTimeZone(); 
16252 		}
16253 		if (params.timezone) {
16254 			this.timezone = params.timezone;
16255 		}
16256 		
16257 		if (params.year || params.month || params.day || params.hour ||
16258 				params.minute || params.second || params.millisecond ) {
16259 			/**
16260 			 * Year in the Ethiopic calendar.
16261 			 * @type number
16262 			 */
16263 			this.year = parseInt(params.year, 10) || 0;
16264 			/**
16265 			 * The month number, ranging from 1 (Maskaram) to 13 (Paguemen).
16266 			 * @type number
16267 			 */
16268 			this.month = parseInt(params.month, 10) || 1;
16269 			/**
16270 			 * The day of the month. This ranges from 1 to 30.
16271 			 * @type number
16272 			 */
16273 			this.day = parseInt(params.day, 10) || 1;
16274 			/**
16275 			 * The hour of the day. This can be a number from 0 to 23, as times are
16276 			 * stored unambiguously in the 24-hour clock.
16277 			 * @type number
16278 			 */
16279 			this.hour = parseInt(params.hour, 10) || 0;
16280 			/**
16281 			 * The minute of the hours. Ranges from 0 to 59.
16282 			 * @type number
16283 			 */
16284 			this.minute = parseInt(params.minute, 10) || 0;
16285 			/**
16286 			 * The second of the minute. Ranges from 0 to 59.
16287 			 * @type number
16288 			 */
16289 			this.second = parseInt(params.second, 10) || 0;
16290 			/**
16291 			 * The millisecond of the second. Ranges from 0 to 999.
16292 			 * @type number
16293 			 */
16294 			this.millisecond = parseInt(params.millisecond, 10) || 0;
16295 			
16296 			/**
16297 			 * The day of the year. Ranges from 1 to 366.
16298 			 * @type number
16299 			 */
16300 			this.dayOfYear = parseInt(params.dayOfYear, 10);
16301 			
16302 			if (typeof(params.dst) === 'boolean') {
16303 				this.dst = params.dst;
16304 			}
16305 			
16306 			this.rd = this.newRd(this);
16307 			
16308 			// add the time zone offset to the rd to convert to UTC
16309 			if (!this.tz) {
16310 				this.tz = new TimeZone({id: this.timezone});
16311 			}
16312 			// getOffsetMillis requires that this.year, this.rd, and this.dst 
16313 			// are set in order to figure out which time zone rules apply and 
16314 			// what the offset is at that point in the year
16315 			this.offset = this.tz._getOffsetMillisWallTime(this) / 86400000;
16316 			if (this.offset !== 0) {
16317 				this.rd = this.newRd({
16318 					rd: this.rd.getRataDie() - this.offset
16319 				});
16320 			}
16321 		}
16322 	}
16323 	
16324 	if (!this.rd) {
16325 		this.rd = this.newRd(params);
16326 		this._calcDateComponents();
16327 	}
16328 };
16329 
16330 EthiopicDate.prototype = new IDate({ noinstance: true });
16331 EthiopicDate.prototype.parent = IDate;
16332 EthiopicDate.prototype.constructor = EthiopicDate;
16333 
16334 /**
16335  * Return a new RD for this date type using the given params.
16336  * @protected
16337  * @param {Object=} params the parameters used to create this rata die instance
16338  * @returns {RataDie} the new RD instance for the given params
16339  */
16340 EthiopicDate.prototype.newRd = function (params) {
16341 	return new EthiopicRataDie(params);
16342 };
16343 
16344 /**
16345  * Return the year for the given RD
16346  * @protected
16347  * @param {number} rd RD to calculate from 
16348  * @returns {number} the year for the RD
16349  */
16350 EthiopicDate.prototype._calcYear = function(rd) {
16351 	var year = Math.floor((4*(Math.floor(rd)-1) + 1463)/1461);
16352 	
16353 	return year;
16354 };
16355 
16356 /**
16357  * Calculate date components for the given RD date.
16358  * @protected
16359  */
16360 EthiopicDate.prototype._calcDateComponents = function () {
16361 	var remainder,
16362 		cumulative,
16363 		rd = this.rd.getRataDie();
16364 	
16365 	this.year = this._calcYear(rd);
16366 
16367 	if (typeof(this.offset) === "undefined") {
16368 		this.year = this._calcYear(rd);
16369 		
16370 		// now offset the RD by the time zone, then recalculate in case we were 
16371 		// near the year boundary
16372 		if (!this.tz) {
16373 			this.tz = new TimeZone({id: this.timezone});
16374 		}
16375 		this.offset = this.tz.getOffsetMillis(this) / 86400000;
16376 	}
16377 
16378 	if (this.offset !== 0) {
16379 		rd += this.offset;
16380 		this.year = this._calcYear(rd);
16381 	}
16382 	
16383 	var jan1 = this.newRd({
16384 		year: this.year,
16385 		month: 1,
16386 		day: 1,
16387 		hour: 0,
16388 		minute: 0,
16389 		second: 0,
16390 		millisecond: 0
16391 	});
16392 	remainder = rd + 1 - jan1.getRataDie();
16393 	
16394 	this.month = Math.floor((remainder-1)/30) + 1;
16395 	remainder = remainder - (this.month-1) * 30;
16396 	
16397 	this.day = Math.floor(remainder);
16398 	remainder -= this.day;
16399 	// now convert to milliseconds for the rest of the calculation
16400 	remainder = Math.round(remainder * 86400000);
16401 	
16402 	this.hour = Math.floor(remainder/3600000);
16403 	remainder -= this.hour * 3600000;
16404 	
16405 	this.minute = Math.floor(remainder/60000);
16406 	remainder -= this.minute * 60000;
16407 	
16408 	this.second = Math.floor(remainder/1000);
16409 	remainder -= this.second * 1000;
16410 	
16411 	this.millisecond = remainder;
16412 };
16413 
16414 /**
16415  * Return the day of the week of this date. The day of the week is encoded
16416  * as number from 0 to 6, with 0=Sunday, 1=Monday, etc., until 6=Saturday.
16417  * 
16418  * @return {number} the day of the week
16419  */
16420 EthiopicDate.prototype.getDayOfWeek = function() {
16421 	var rd = Math.floor(this.rd.getRataDie() + (this.offset || 0));
16422 	return MathUtils.mod(rd-4, 7);
16423 };
16424 
16425 /**
16426  * Return the name of the calendar that governs this date.
16427  * 
16428  * @return {string} a string giving the name of the calendar
16429  */
16430 EthiopicDate.prototype.getCalendar = function() {
16431 	return "ethiopic";
16432 };
16433 
16434 //register with the factory method
16435 IDate._constructors["ethiopic"] = EthiopicDate;
16436 
16437 
16438 
16439 /*< CopticCal.js */
16440 /*
16441  * coptic.js - Represent a Coptic calendar object.
16442  * 
16443  * Copyright © 2015, JEDLSoft
16444  *
16445  * Licensed under the Apache License, Version 2.0 (the "License");
16446  * you may not use this file except in compliance with the License.
16447  * You may obtain a copy of the License at
16448  *
16449  *     http://www.apache.org/licenses/LICENSE-2.0
16450  *
16451  * Unless required by applicable law or agreed to in writing, software
16452  * distributed under the License is distributed on an "AS IS" BASIS,
16453  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16454  *
16455  * See the License for the specific language governing permissions and
16456  * limitations under the License.
16457  */
16458 
16459 
16460 /* !depends ilib.js Calendar.js Locale.js Utils.js EthiopicCal.js */
16461 
16462 
16463 /**
16464  * @class
16465  * Construct a new Coptic calendar object. This class encodes information about
16466  * a Coptic calendar.<p>
16467  * 
16468  * 
16469  * @constructor
16470  * @extends EthiopicCal
16471  */
16472 var CopticCal = function() {
16473 	this.type = "coptic";
16474 };
16475 
16476 CopticCal.prototype = new EthiopicCal();
16477 CopticCal.prototype.parent = EthiopicCal;
16478 CopticCal.prototype.constructor = CopticCal;
16479 
16480 /**
16481  * Return a date instance for this calendar type using the given
16482  * options.
16483  * @param {Object} options options controlling the construction of 
16484  * the date instance
16485  * @return {IDate} a date appropriate for this calendar type
16486  * @deprecated Since 11.0.5. Use DateFactory({calendar: cal.getType(), ...}) instead
16487  */
16488 CopticCal.prototype.newDateInstance = function (options) {
16489 		return new CopticDate(options);
16490 };
16491 
16492 /* register this calendar for the factory method */
16493 Calendar._constructors["coptic"] = CopticCal;
16494 
16495 
16496 /*< CopticRataDie.js */
16497 /*
16498  * CopticRataDie.js - Represent an RD date in the Coptic calendar
16499  * 
16500  * Copyright © 2015, JEDLSoft
16501  *
16502  * Licensed under the Apache License, Version 2.0 (the "License");
16503  * you may not use this file except in compliance with the License.
16504  * You may obtain a copy of the License at
16505  *
16506  *     http://www.apache.org/licenses/LICENSE-2.0
16507  *
16508  * Unless required by applicable law or agreed to in writing, software
16509  * distributed under the License is distributed on an "AS IS" BASIS,
16510  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16511  *
16512  * See the License for the specific language governing permissions and
16513  * limitations under the License.
16514  */
16515 
16516 /* !depends 
16517 ilib.js
16518 CopticCal.js 
16519 JSUtils.js
16520 EthiopicRataDie.js
16521 */
16522 
16523 
16524 /**
16525  * @class
16526  * Construct a new Coptic RD date number object. The constructor parameters can 
16527  * contain any of the following properties:
16528  * 
16529  * <ul>
16530  * <li><i>unixtime<i> - sets the time of this instance according to the given 
16531  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970.
16532  * 
16533  * <li><i>julianday</i> - sets the time of this instance according to the given
16534  * Julian Day instance or the Julian Day given as a float
16535  * 
16536  * <li><i>year</i> - any integer, including 0
16537  * 
16538  * <li><i>month</i> - 1 to 13, where 1 means Thoout, 2 means Paope, etc., and 13 means Epagomene
16539  * 
16540  * <li><i>day</i> - 1 to 30
16541  * 
16542  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
16543  * is always done with an unambiguous 24 hour representation
16544  * 
16545  * <li><i>minute</i> - 0 to 59
16546  * 
16547  * <li><i>second</i> - 0 to 59
16548  * 
16549  * <li><i>millisecond</i> - 0 to 999
16550  * 
16551  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
16552  * </ul>
16553  *
16554  * If the constructor is called with another Coptic date instance instead of
16555  * a parameter block, the other instance acts as a parameter block and its
16556  * settings are copied into the current instance.<p>
16557  * 
16558  * If the constructor is called with no arguments at all or if none of the 
16559  * properties listed above are present, then the RD is calculate based on 
16560  * the current date at the time of instantiation. <p>
16561  * 
16562  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
16563  * specified in the params, it is assumed that they have the smallest possible
16564  * value in the range for the property (zero or one).<p>
16565  * 
16566  * 
16567  * @private
16568  * @constructor
16569  * @extends EthiopicRataDie
16570  * @param {Object=} params parameters that govern the settings and behaviour of this Coptic RD date
16571  */
16572 var CopticRataDie = function(params) {
16573 	this.cal = params && params.cal || new CopticCal();
16574 	this.rd = NaN;
16575 	/**
16576 	 * The difference between the zero Julian day and the first Coptic date
16577 	 * of Friday, August 29, 284 CE Julian at 7:00am UTC. 
16578 	 * @private
16579 	 * @type number
16580 	 */
16581 	this.epoch = 1825028.5;
16582 
16583 	var tmp = {};
16584 	if (params) {
16585 		JSUtils.shallowCopy(params, tmp);
16586 	}
16587 	tmp.cal = this.cal; // override the cal parameter that may be passed in
16588 	EthiopicRataDie.call(this, tmp);
16589 };
16590 
16591 CopticRataDie.prototype = new EthiopicRataDie();
16592 CopticRataDie.prototype.parent = EthiopicRataDie;
16593 CopticRataDie.prototype.constructor = CopticRataDie;
16594 
16595 
16596 /*< CopticDate.js */
16597 /*
16598  * CopticDate.js - Represent a date in the Coptic calendar
16599  * 
16600  * Copyright © 2015, JEDLSoft
16601  *
16602  * Licensed under the Apache License, Version 2.0 (the "License");
16603  * you may not use this file except in compliance with the License.
16604  * You may obtain a copy of the License at
16605  *
16606  *     http://www.apache.org/licenses/LICENSE-2.0
16607  *
16608  * Unless required by applicable law or agreed to in writing, software
16609  * distributed under the License is distributed on an "AS IS" BASIS,
16610  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16611  *
16612  * See the License for the specific language governing permissions and
16613  * limitations under the License.
16614  */
16615 
16616 /* !depends 
16617 ilib.js
16618 IDate.js 
16619 CopticCal.js 
16620 MathUtils.js
16621 JSUtils.js
16622 Locale.js
16623 LocaleInfo.js 
16624 TimeZone.js
16625 EthiopicDate.js
16626 CopticRataDie.js
16627 */
16628 
16629 
16630 
16631 
16632 /**
16633  * @class
16634  * Construct a new date object for the Coptic Calendar. The constructor can be called
16635  * with a parameter object that contains any of the following properties:
16636  * 
16637  * <ul>
16638  * <li><i>unixtime<i> - sets the time of this instance according to the given 
16639  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970 (Gregorian).
16640  * <li><i>julianday</i> - the Julian Day to set into this date
16641  * <li><i>year</i> - any integer
16642  * <li><i>month</i> - 1 to 13, where 1 means Thoout, 2 means Paope, etc., and 13 means Epagomene
16643  * <li><i>day</i> - 1 to 30
16644  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
16645  * is always done with an unambiguous 24 hour representation
16646  * <li><i>minute</i> - 0 to 59
16647  * <li><i>second</i> - 0 to 59
16648  * <li><i>millisecond<i> - 0 to 999
16649  * <li><i>locale</i> - the TimeZone instance or time zone name as a string 
16650  * of this coptic date. The date/time is kept in the local time. The time zone
16651  * is used later if this date is formatted according to a different time zone and
16652  * the difference has to be calculated, or when the date format has a time zone
16653  * component in it.
16654  * <li><i>timezone</i> - the time zone of this instance. If the time zone is not 
16655  * given, it can be inferred from this locale. For locales that span multiple
16656  * time zones, the one with the largest population is chosen as the one that 
16657  * represents the locale. 
16658  * 
16659  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
16660  * </ul>
16661  *  
16662  * If called with another Coptic date argument, the date components of the given
16663  * date are copied into the current one.<p>
16664  * 
16665  * If the constructor is called with no arguments at all or if none of the 
16666  * properties listed above 
16667  * from <i>unixtime</i> through <i>millisecond</i> are present, then the date 
16668  * components are 
16669  * filled in with the current date at the time of instantiation. Note that if
16670  * you do not give the time zone when defaulting to the current time and the 
16671  * time zone for all of ilib was not set with <i>ilib.setTimeZone()</i>, then the
16672  * time zone will default to UTC ("Universal Time, Coordinated" or "Greenwich 
16673  * Mean Time").<p>
16674  * 
16675  * 
16676  * @constructor
16677  * @extends EthiopicDate
16678  * @param {Object=} params parameters that govern the settings and behaviour of this Coptic date
16679  */
16680 var CopticDate = function(params) {
16681 	this.rd = NaN; // clear these out so that the EthiopicDate constructor can set it
16682 	EthiopicDate.call(this, params);
16683 	this.cal = new CopticCal();
16684 };
16685 
16686 CopticDate.prototype = new EthiopicDate({noinstance: true});
16687 CopticDate.prototype.parent = EthiopicDate.prototype;
16688 CopticDate.prototype.constructor = CopticDate;
16689 
16690 /**
16691  * Return a new RD for this date type using the given params.
16692  * @protected
16693  * @param {Object=} params the parameters used to create this rata die instance
16694  * @returns {RataDie} the new RD instance for the given params
16695  */
16696 CopticDate.prototype.newRd = function (params) {
16697 	return new CopticRataDie(params);
16698 };
16699 
16700 /**
16701  * Return the day of the week of this date. The day of the week is encoded
16702  * as number from 0 to 6, with 0=Sunday, 1=Monday, etc., until 6=Saturday.
16703  * 
16704  * @return {number} the day of the week
16705  */
16706 CopticDate.prototype.getDayOfWeek = function() {
16707 	var rd = Math.floor(this.rd.getRataDie() + (this.offset || 0));
16708 	return MathUtils.mod(rd-3, 7);
16709 };
16710 
16711 /**
16712  * Return the name of the calendar that governs this date.
16713  * 
16714  * @return {string} a string giving the name of the calendar
16715  */
16716 CopticDate.prototype.getCalendar = function() {
16717 	return "coptic";
16718 };
16719 
16720 //register with the factory method
16721 IDate._constructors["coptic"] = CopticDate;
16722 
16723 
16724 /*< CType.js */
16725 /*
16726  * CType.js - Character type definitions
16727  * 
16728  * Copyright © 2012-2015, JEDLSoft
16729  *
16730  * Licensed under the Apache License, Version 2.0 (the "License");
16731  * you may not use this file except in compliance with the License.
16732  * You may obtain a copy of the License at
16733  *
16734  *     http://www.apache.org/licenses/LICENSE-2.0
16735  *
16736  * Unless required by applicable law or agreed to in writing, software
16737  * distributed under the License is distributed on an "AS IS" BASIS,
16738  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16739  *
16740  * See the License for the specific language governing permissions and
16741  * limitations under the License.
16742  */
16743 
16744 // !depends ilib.js Locale.js SearchUtils.js Utils.js IString.js
16745 
16746 // !data ctype
16747 
16748 
16749 /**
16750  * Provides a set of static routines that return information about characters.
16751  * These routines emulate the C-library ctype functions. The characters must be 
16752  * encoded in utf-16, as no other charsets are currently supported. Only the first
16753  * character of the given string is tested.
16754  * @namespace
16755  */
16756 var CType = {};
16757 
16758 
16759 /**
16760  * Actual implementation for withinRange. Searches the given object for ranges.
16761  * The range names are taken from the Unicode range names in 
16762  * http://www.unicode.org/Public/UNIDATA/extracted/DerivedGeneralCategory.txt
16763  * 
16764  * <ul>
16765  * <li>Cn - Unassigned
16766  * <li>Lu - Uppercase_Letter
16767  * <li>Ll - Lowercase_Letter
16768  * <li>Lt - Titlecase_Letter
16769  * <li>Lm - Modifier_Letter
16770  * <li>Lo - Other_Letter
16771  * <li>Mn - Nonspacing_Mark
16772  * <li>Me - Enclosing_Mark
16773  * <li>Mc - Spacing_Mark
16774  * <li>Nd - Decimal_Number
16775  * <li>Nl - Letter_Number
16776  * <li>No - Other_Number
16777  * <li>Zs - Space_Separator
16778  * <li>Zl - Line_Separator
16779  * <li>Zp - Paragraph_Separator
16780  * <li>Cc - Control
16781  * <li>Cf - Format
16782  * <li>Co - Private_Use
16783  * <li>Cs - Surrogate
16784  * <li>Pd - Dash_Punctuation
16785  * <li>Ps - Open_Punctuation
16786  * <li>Pe - Close_Punctuation
16787  * <li>Pc - Connector_Punctuation
16788  * <li>Po - Other_Punctuation
16789  * <li>Sm - Math_Symbol
16790  * <li>Sc - Currency_Symbol
16791  * <li>Sk - Modifier_Symbol
16792  * <li>So - Other_Symbol
16793  * <li>Pi - Initial_Punctuation
16794  * <li>Pf - Final_Punctuation
16795  * </ul>
16796  * 
16797  * @protected
16798  * @param {number} num code point of the character to examine
16799  * @param {string} rangeName the name of the range to check
16800  * @param {Object} obj object containing the character range data
16801  * @return {boolean} true if the first character is within the named
16802  * range
16803  */
16804 CType._inRange = function(num, rangeName, obj) {
16805 	var range, i;
16806 	if (num < 0 || !rangeName || !obj) {
16807 		return false;
16808 	}
16809 	
16810 	range = obj[rangeName];
16811 	if (!range) {
16812 		return false;
16813 	}
16814 	
16815 	var compare = function(singlerange, target) {
16816 		if (singlerange.length === 1) {
16817 			return singlerange[0] - target;
16818 		} else {
16819 			return target < singlerange[0] ? singlerange[0] - target :
16820 				(target > singlerange[1] ? singlerange[1] - target : 0);
16821 		}
16822 	};
16823 	var result = SearchUtils.bsearch(num, range, compare);
16824 	return result < range.length && compare(range[result], num) === 0;
16825 };
16826 
16827 /**
16828  * Return whether or not the first character is within the named range
16829  * of Unicode characters. The valid list of range names are taken from 
16830  * the Unicode 6.0 spec. Characters in all ranges of Unicode are supported,
16831  * including those supported in Javascript via UTF-16. Currently, this method 
16832  * supports the following range names:
16833  * 
16834  * <ul>
16835  * <li><i>ascii</i> - basic ASCII
16836  * <li><i>latin</i> - Latin, Latin Extended Additional, Latin-1 supplement, Latin Extended-C, Latin Extended-D, Latin Extended-E
16837  * <li><i>armenian</i>
16838  * <li><i>greek</i> - Greek, Greek Extended
16839  * <li><i>cyrillic</i> - Cyrillic, Cyrillic Extended-A, Cyrillic Extended-B, Cyrillic Supplement
16840  * <li><i>georgian</i> - Georgian, Georgian Supplement
16841  * <li><i>glagolitic</i>
16842  * <li><i>gothic</i>
16843  * <li><i>ogham</i>
16844  * <li><i>oldpersian</i>
16845  * <li><i>runic</i>
16846  * <li><i>ipa</i> - IPA, Phonetic Extensions, Phonetic Extensions Supplement
16847  * <li><i>phonetic</i>
16848  * <li><i>modifiertone</i> - Modifier Tone Letters
16849  * <li><i>spacing</i>
16850  * <li><i>diacritics</i>
16851  * <li><i>halfmarks</i> - Combining Half Marks
16852  * <li><i>small</i> - Small Form Variants
16853  * <li><i>bamum</i> - Bamum, Bamum Supplement
16854  * <li><i>ethiopic</i> - Ethiopic, Ethiopic Extended, Ethiopic Extended-A
16855  * <li><i>nko</i>
16856  * <li><i>osmanya</i>
16857  * <li><i>tifinagh</i>
16858  * <li><i>val</i>
16859  * <li><i>arabic</i> - Arabic, Arabic Supplement, Arabic Presentation Forms-A, 
16860  * Arabic Presentation Forms-B, Arabic Mathematical Alphabetic Symbols
16861  * <li><i>carlan</i>
16862  * <li><i>hebrew</i>
16863  * <li><i>mandaic</i>
16864  * <li><i>samaritan</i>
16865  * <li><i>syriac</i>
16866  * <li><i>mongolian</i>
16867  * <li><i>phagspa</i>
16868  * <li><i>tibetan</i>
16869  * <li><i>bengali</i>
16870  * <li><i>devanagari</i> - Devanagari, Devanagari Extended
16871  * <li><i>gujarati</i>
16872  * <li><i>gurmukhi</i>
16873  * <li><i>kannada</i>
16874  * <li><i>lepcha</i>
16875  * <li><i>limbu</i>
16876  * <li><i>malayalam</i>
16877  * <li><i>meetaimayek</i>
16878  * <li><i>olchiki</i>
16879  * <li><i>oriya</i>
16880  * <li><i>saurashtra</i>
16881  * <li><i>sinhala</i>
16882  * <li><i>sylotinagri</i> - Syloti Nagri
16883  * <li><i>tamil</i>
16884  * <li><i>telugu</i>
16885  * <li><i>thaana</i>
16886  * <li><i>vedic</i>
16887  * <li><i>batak</i>
16888  * <li><i>balinese</i>
16889  * <li><i>buginese</i>
16890  * <li><i>cham</i>
16891  * <li><i>javanese</i>
16892  * <li><i>kayahli</i>
16893  * <li><i>khmer</i>
16894  * <li><i>lao</i>
16895  * <li><i>myanmar</i> - Myanmar, Myanmar Extended-A, Myanmar Extended-B
16896  * <li><i>newtailue</i>
16897  * <li><i>rejang</i>
16898  * <li><i>sundanese</i> - Sundanese, Sundanese Supplement
16899  * <li><i>taile</i>
16900  * <li><i>taitham</i>
16901  * <li><i>taiviet</i>
16902  * <li><i>thai</i>
16903  * <li><i>buhld</i>
16904  * <li><i>hanunoo</i>
16905  * <li><i>tagalog</i>
16906  * <li><i>tagbanwa</i>
16907  * <li><i>bopomofo</i> - Bopomofo, Bopomofo Extended
16908  * <li><i>cjk</i> - the CJK unified ideographs (Han), CJK Unified Ideographs
16909  *  Extension A, CJK Unified Ideographs Extension B, CJK Unified Ideographs 
16910  *  Extension C, CJK Unified Ideographs Extension D, Ideographic Description 
16911  *  Characters (=isIdeo())
16912  * <li><i>cjkcompatibility</i> - CJK Compatibility, CJK Compatibility 
16913  * Ideographs, CJK Compatibility Forms, CJK Compatibility Ideographs Supplement
16914  * <li><i>cjkradicals</i> - the CJK radicals, KangXi radicals
16915  * <li><i>hangul</i> - Hangul Jamo, Hangul Syllables, Hangul Jamo Extended-A, 
16916  * Hangul Jamo Extended-B, Hangul Compatibility Jamo
16917  * <li><i>cjkpunct</i> - CJK symbols and punctuation
16918  * <li><i>cjkstrokes</i> - CJK strokes
16919  * <li><i>hiragana</i>
16920  * <li><i>katakana</i> - Katakana, Katakana Phonetic Extensions, Kana Supplement
16921  * <li><i>kanbun</i>
16922  * <li><i>lisu</i>
16923  * <li><i>yi</i> - Yi Syllables, Yi Radicals
16924  * <li><i>cherokee</i>
16925  * <li><i>canadian</i> - Unified Canadian Aboriginal Syllabics, Unified Canadian 
16926  * Aboriginal Syllabics Extended
16927  * <li><i>presentation</i> - Alphabetic presentation forms
16928  * <li><i>vertical</i> - Vertical Forms
16929  * <li><i>width</i> - Halfwidth and Fullwidth Forms
16930  * <li><i>punctuation</i> - General punctuation, Supplemental Punctuation
16931  * <li><i>box</i> - Box Drawing
16932  * <li><i>block</i> - Block Elements
16933  * <li><i>letterlike</i> - Letterlike symbols
16934  * <li><i>mathematical</i> - Mathematical alphanumeric symbols, Miscellaneous 
16935  * Mathematical Symbols-A, Miscellaneous Mathematical Symbols-B
16936  * <li><i>enclosedalpha</i> - Enclosed alphanumerics, Enclosed Alphanumeric Supplement
16937  * <li><i>enclosedcjk</i> - Enclosed CJK letters and months, Enclosed Ideographic Supplement
16938  * <li><i>cjkcompatibility</i> - CJK compatibility
16939  * <li><i>apl</i> - APL symbols
16940  * <li><i>controlpictures</i> - Control pictures
16941  * <li><i>misc</i> - Miscellaneous technical
16942  * <li><i>ocr</i> - Optical character recognition (OCR)
16943  * <li><i>combining</i> - Combining Diacritical Marks, Combining Diacritical Marks 
16944  * for Symbols, Combining Diacritical Marks Supplement, Combining Diacritical Marks Extended
16945  * <li><i>digits</i> - ASCII digits (=isDigit())
16946  * <li><i>indicnumber</i> - Common Indic Number Forms
16947  * <li><i>numbers</i> - Number forms
16948  * <li><i>supersub</i> - Superscripts and Subscripts
16949  * <li><i>arrows</i> - Arrows, Miscellaneous Symbols and Arrows, Supplemental Arrows-A,
16950  * Supplemental Arrows-B, Supplemental Arrows-C
16951  * <li><i>operators</i> - Mathematical operators, supplemental 
16952  * mathematical operators 
16953  * <li><i>geometric</i> - Geometric shapes, Geometric shapes extended
16954  * <li><i>ancient</i> - Ancient symbols
16955  * <li><i>braille</i> - Braille patterns
16956  * <li><i>currency</i> - Currency symbols
16957  * <li><i>dingbats</i>
16958  * <li><i>gamesymbols</i>
16959  * <li><i>yijing</i> - Yijing Hexagram Symbols
16960  * <li><i>specials</i>
16961  * <li><i>variations</i> - Variation Selectors, Variation Selectors Supplement
16962  * <li><i>privateuse</i> - Private Use Area, Supplementary Private Use Area-A, 
16963  * Supplementary Private Use Area-B
16964  * <li><i>supplementarya</i> - Supplementary private use area-A
16965  * <li><i>supplementaryb</i> - Supplementary private use area-B
16966  * <li><i>highsurrogates</i> - High Surrogates, High Private Use Surrogates
16967  * <li><i>lowsurrogates</i>
16968  * <li><i>reserved</i>
16969  * <li><i>noncharacters</i>
16970  * <li><i>copticnumber</i> - coptic epact numbers
16971  * <li><i>oldpermic</i> - old permic
16972  * <li><i>albanian</i> - albanian
16973  * <li><i>lineara</i> - linear a
16974  * <li><i>meroitic</i> - meroitic cursive
16975  * <li><i>oldnortharabian</i> - old north arabian
16976  * <li><i>oldhungarian</i> - Supplementary private use area-A
16977  * <li><i>sorasompeng</i> - sora sompeng
16978  * <li><i>warangciti</i> - warang citi
16979  * <li><i>paucinhau</i> - pau cin hau
16980  * <li><i>bassavah</i> - bassa vah
16981  * <li><i>pahawhhmong</i> - pahawh hmong
16982  * <li><i>shorthandformat</i> - shorthand format controls
16983  * <li><i>suttonsignwriting</i> - sutton signwriting
16984  * <li><i>pictographs</i> - miscellaneous symbols and pictographs, supplemental symbols and pictographs
16985  * <li><i>ornamentaldingbats</i> - ornamental dingbats
16986  * </ul><p>
16987  * 
16988  * 
16989  * @protected
16990  * @param {string|IString|number} ch character or code point to examine
16991  * @param {string} rangeName the name of the range to check
16992  * @return {boolean} true if the first character is within the named
16993  * range
16994  */
16995 CType.withinRange = function(ch, rangeName) {
16996 	if (!rangeName) {
16997 		return false;
16998 	}
16999 	var num;
17000 	switch (typeof(ch)) {
17001 		case 'number':
17002 			num = ch;
17003 			break;
17004 		case 'string':
17005 			num = IString.toCodePoint(ch, 0);
17006 			break;
17007 		case 'undefined':
17008 			return false;
17009 		default:
17010 			num = ch._toCodePoint(0);
17011 			break;
17012 	}
17013 
17014 	return CType._inRange(num, rangeName.toLowerCase(), ilib.data.ctype);
17015 };
17016 
17017 /**
17018  * @protected
17019  * @param {boolean} sync
17020  * @param {Object|undefined} loadParams
17021  * @param {function(*)|undefined} onLoad
17022  */
17023 CType._init = function(sync, loadParams, onLoad) {
17024 	CType._load("ctype", sync, loadParams, onLoad);
17025 };
17026 
17027 /**
17028  * @protected
17029  * @param {string} name
17030  * @param {boolean} sync
17031  * @param {Object|undefined} loadParams
17032  * @param {function(*)|undefined} onLoad
17033  */
17034 CType._load = function (name, sync, loadParams, onLoad) {
17035 	if (!ilib.data[name]) {
17036 		var loadName = name ? name + ".json" : "CType.json";
17037 		Utils.loadData({
17038 			name: loadName,
17039 			locale: "-",
17040 			nonlocale: true,
17041 			sync: sync,
17042 			loadParams: loadParams, 
17043 			callback: ilib.bind(this, function(ct) {
17044 				ilib.data[name] = ct;
17045 				if (onLoad && typeof(onLoad) === 'function') {
17046 					onLoad(ilib.data[name]);
17047 				}
17048 			})
17049 		});
17050 	} else {
17051 		if (onLoad && typeof(onLoad) === 'function') {
17052 			onLoad(ilib.data[name]);
17053 		}
17054 	}
17055 };
17056 
17057 
17058 
17059 /*< isDigit.js */
17060 /*
17061  * isDigit.js - Character type is digit
17062  * 
17063  * Copyright © 2012-2015, JEDLSoft
17064  *
17065  * Licensed under the Apache License, Version 2.0 (the "License");
17066  * you may not use this file except in compliance with the License.
17067  * You may obtain a copy of the License at
17068  *
17069  *     http://www.apache.org/licenses/LICENSE-2.0
17070  *
17071  * Unless required by applicable law or agreed to in writing, software
17072  * distributed under the License is distributed on an "AS IS" BASIS,
17073  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17074  *
17075  * See the License for the specific language governing permissions and
17076  * limitations under the License.
17077  */
17078 
17079 // !depends CType.js IString.js ilib.js
17080 
17081 // !data ctype
17082 
17083 
17084 /**
17085  * Return whether or not the first character is a digit character in the
17086  * Latin script.<p>
17087  * 
17088  * @static
17089  * @param {string|IString|number} ch character or code point to examine
17090  * @return {boolean} true if the first character is a digit character in the
17091  * Latin script. 
17092  */
17093 var isDigit = function (ch) {
17094 	var num;
17095 	switch (typeof(ch)) {
17096 		case 'number':
17097 			num = ch;
17098 			break;
17099 		case 'string':
17100 			num = IString.toCodePoint(ch, 0);
17101 			break;
17102 		case 'undefined':
17103 			return false;
17104 		default:
17105 			num = ch._toCodePoint(0);
17106 			break;
17107 	}
17108 	return CType._inRange(num, 'digit', ilib.data.ctype);
17109 };
17110 
17111 /**
17112  * @protected
17113  * @param {boolean} sync
17114  * @param {Object|undefined} loadParams
17115  * @param {function(*)|undefined} onLoad
17116  */
17117 isDigit._init = function (sync, loadParams, onLoad) {
17118 	CType._init(sync, loadParams, onLoad);
17119 };
17120 
17121 
17122 
17123 /*< isSpace.js */
17124 /*
17125  * isSpace.js - Character type is space char
17126  * 
17127  * Copyright © 2012-2015, JEDLSoft
17128  *
17129  * Licensed under the Apache License, Version 2.0 (the "License");
17130  * you may not use this file except in compliance with the License.
17131  * You may obtain a copy of the License at
17132  *
17133  *     http://www.apache.org/licenses/LICENSE-2.0
17134  *
17135  * Unless required by applicable law or agreed to in writing, software
17136  * distributed under the License is distributed on an "AS IS" BASIS,
17137  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17138  *
17139  * See the License for the specific language governing permissions and
17140  * limitations under the License.
17141  */
17142 
17143 // !depends CType.js IString.js
17144 
17145 // !data ctype ctype_z
17146 
17147 
17148 
17149 /**
17150  * Return whether or not the first character is a whitespace character.<p>
17151  * 
17152  * @static
17153  * @param {string|IString|number} ch character or code point to examine
17154  * @return {boolean} true if the first character is a whitespace character.
17155  */
17156 var isSpace = function (ch) {
17157 	var num;
17158 	switch (typeof(ch)) {
17159 		case 'number':
17160 			num = ch;
17161 			break;
17162 		case 'string':
17163 			num = IString.toCodePoint(ch, 0);
17164 			break;
17165 		case 'undefined':
17166 			return false;
17167 		default:
17168 			num = ch._toCodePoint(0);
17169 			break;
17170 	}
17171 
17172 	return CType._inRange(num, 'space', ilib.data.ctype) ||
17173 		CType._inRange(num, 'Zs', ilib.data.ctype_z) ||
17174 		CType._inRange(num, 'Zl', ilib.data.ctype_z) ||
17175 		CType._inRange(num, 'Zp', ilib.data.ctype_z);
17176 };
17177 
17178 /**
17179  * @protected
17180  * @param {boolean} sync
17181  * @param {Object|undefined} loadParams
17182  * @param {function(*)|undefined} onLoad
17183  */
17184 isSpace._init = function (sync, loadParams, onLoad) {
17185 	CType._load("ctype_z", sync, loadParams, function () {
17186 		CType._init(sync, loadParams, onLoad);
17187 	});
17188 };
17189 
17190 
17191 /*< Currency.js */
17192 /*
17193  * Currency.js - Currency definition
17194  * 
17195  * Copyright © 2012-2015, JEDLSoft
17196  *
17197  * Licensed under the Apache License, Version 2.0 (the "License");
17198  * you may not use this file except in compliance with the License.
17199  * You may obtain a copy of the License at
17200  *
17201  *     http://www.apache.org/licenses/LICENSE-2.0
17202  *
17203  * Unless required by applicable law or agreed to in writing, software
17204  * distributed under the License is distributed on an "AS IS" BASIS,
17205  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17206  *
17207  * See the License for the specific language governing permissions and
17208  * limitations under the License.
17209  */
17210 
17211 // !depends ilib.js Utils.js Locale.js LocaleInfo.js
17212 
17213 // !data currency
17214 
17215 
17216 /**
17217  * @class
17218  * Create a new currency information instance. Instances of this class encode 
17219  * information about a particular currency.<p>
17220  * 
17221  * Note: that if you are looking to format currency for display, please see
17222  * the number formatting class {NumFmt}. This class only gives information
17223  * about currencies.<p> 
17224  * 
17225  * The options can contain any of the following properties:
17226  * 
17227  * <ul>
17228  * <li><i>locale</i> - specify the locale for this instance
17229  * <li><i>code</i> - find info on a specific currency with the given ISO 4217 code 
17230  * <li><i>sign</i> - search for a currency that uses this sign
17231  * <li><i>onLoad</i> - a callback function to call when the currency data is fully 
17232  * loaded. When the onLoad option is given, this class will attempt to
17233  * load any missing locale data using the ilib loader callback.
17234  * When the constructor is done (even if the data is already preassembled), the 
17235  * onLoad function is called with the current instance as a parameter, so this
17236  * callback can be used with preassembled or dynamic loading or a mix of the two. 
17237  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
17238  * asynchronously. If this option is given as "false", then the "onLoad"
17239  * callback must be given, as the instance returned from this constructor will
17240  * not be usable for a while.
17241  * <li><i>loadParams</i> - an object containing parameters to pass to the 
17242  * loader callback function when locale data is missing. The parameters are not
17243  * interpretted or modified in any way. They are simply passed along. The object 
17244  * may contain any property/value pairs as long as the calling code is in
17245  * agreement with the loader callback function as to what those parameters mean.
17246  * </ul>
17247  * 
17248  * When searching for a currency by its sign, this class cannot guarantee 
17249  * that it will return info about a specific currency. The reason is that currency 
17250  * signs are sometimes shared between different currencies and the sign is 
17251  * therefore ambiguous. If you need a 
17252  * guarantee, find the currency using the code instead.<p>
17253  * 
17254  * The way this class finds a currency by sign is the following. If the sign is 
17255  * unambiguous, then
17256  * the currency is returned. If there are multiple currencies that use the same
17257  * sign, and the current locale uses that sign, then the default currency for
17258  * the current locale is returned. If there are multiple, but the current locale
17259  * does not use that sign, then the currency with the largest circulation is
17260  * returned. For example, if you are in the en-GB locale, and the sign is "$",
17261  * then this class will notice that there are multiple currencies with that
17262  * sign (USD, CAD, AUD, HKD, MXP, etc.) Since "$" is not used in en-GB, it will 
17263  * pick the one with the largest circulation, which in this case is the US Dollar
17264  * (USD).<p>
17265  * 
17266  * If neither the code or sign property is set, the currency that is most common 
17267  * for the locale
17268  * will be used instead. If the locale is not set, the default locale will be used.
17269  * If the code is given, but it is not found in the list of known currencies, this
17270  * constructor will throw an exception. If the sign is given, but it is not found,
17271  * this constructor will default to the currency for the current locale. If both
17272  * the code and sign properties are given, then the sign property will be ignored
17273  * and only the code property used. If the locale is given, but it is not a known
17274  * locale, this class will default to the default locale instead.<p>
17275  * 
17276  * 
17277  * @constructor
17278  * @param options {Object} a set of properties to govern how this instance is constructed.
17279  * @throws "currency xxx is unknown" when the given currency code is not in the list of 
17280  * known currencies. xxx is replaced with the requested code.
17281  */
17282 var Currency = function (options) {
17283 	this.sync = true;
17284 	
17285 	if (options) {
17286 		if (options.code) {
17287 			this.code = options.code;
17288 		}
17289 		if (options.locale) {
17290 			this.locale = (typeof(options.locale) === 'string') ? new Locale(options.locale) : options.locale;
17291 		}
17292 		if (options.sign) {
17293 			this.sign = options.sign;
17294 		}
17295 		if (typeof(options.sync) !== 'undefined') {
17296 			this.sync = options.sync;
17297 		}
17298 		if (options.loadParams) {
17299 			this.loadParams = options.loadParams;
17300 		}
17301 	}
17302 	
17303 	this.locale = this.locale || new Locale();
17304 	if (typeof(ilib.data.currency) === 'undefined') {
17305 		Utils.loadData({
17306 			name: "currency.json",
17307 			object: Currency, 
17308 			locale: "-",
17309 			sync: this.sync, 
17310 			loadParams: this.loadParams, 
17311 			callback: ilib.bind(this, function(currency) {
17312 				ilib.data.currency = currency;
17313 				this._loadLocinfo(options && options.onLoad);
17314 			})
17315 		});
17316 	} else {
17317 		this._loadLocinfo(options && options.onLoad);
17318 	}
17319 };
17320 
17321 /**
17322  * Return an array of the ids for all ISO 4217 currencies that
17323  * this copy of ilib knows about.
17324  * 
17325  * @static
17326  * @return {Array.<string>} an array of currency ids that this copy of ilib knows about.
17327  */
17328 Currency.getAvailableCurrencies = function() {
17329 	var ret = [],
17330 		cur,
17331 		currencies = new ResBundle({
17332 			name: "currency"
17333 		}).getResObj();
17334 	
17335 	for (cur in currencies) {
17336 		if (cur && currencies[cur]) {
17337 			ret.push(cur);
17338 		}
17339 	}
17340 	
17341 	return ret;
17342 };
17343 
17344 Currency.prototype = {
17345 	/**
17346 	 * @private
17347 	 */
17348 	_loadLocinfo: function(onLoad) {
17349 		new LocaleInfo(this.locale, {
17350 			onLoad: ilib.bind(this, function (li) {
17351 				var currInfo;
17352 				
17353 				this.locinfo = li;
17354 		    	if (this.code) {
17355 		    		currInfo = ilib.data.currency[this.code];
17356 		    		if (!currInfo) {
17357 		    			throw "currency " + this.code + " is unknown";
17358 		    		}
17359 		    	} else if (this.sign) {
17360 		    		currInfo = ilib.data.currency[this.sign]; // maybe it is really a code...
17361 		    		if (typeof(currInfo) !== 'undefined') {
17362 		    			this.code = this.sign;
17363 		    		} else {
17364 		    			this.code = this.locinfo.getCurrency();
17365 		    			currInfo = ilib.data.currency[this.code];
17366 		    			if (currInfo.sign !== this.sign) {
17367 		    				// current locale does not use the sign, so search for it
17368 		    				for (var cur in ilib.data.currency) {
17369 		    					if (cur && ilib.data.currency[cur]) {
17370 		    						currInfo = ilib.data.currency[cur];
17371 		    						if (currInfo.sign === this.sign) {
17372 		    							// currency data is already ordered so that the currency with the
17373 		    							// largest circulation is at the beginning, so all we have to do
17374 		    							// is take the first one in the list that matches
17375 		    							this.code = cur;
17376 		    							break;
17377 		    						}
17378 		    					}
17379 		    				}
17380 		    			}
17381 		    		}
17382 		    	}
17383 		    	
17384 		    	if (!currInfo || !this.code) {
17385 		    		this.code = this.locinfo.getCurrency();
17386 		    		currInfo = ilib.data.currency[this.code];
17387 		    	}
17388 		    	
17389 		    	this.name = currInfo.name;
17390 		    	this.fractionDigits = currInfo.decimals;
17391 		    	this.sign = currInfo.sign;
17392 		    	
17393 				if (typeof(onLoad) === 'function') {
17394 					onLoad(this);
17395 				}
17396 			})
17397 		});
17398 	},
17399 	
17400 	/**
17401 	 * Return the ISO 4217 currency code for this instance.
17402 	 * @return {string} the ISO 4217 currency code for this instance
17403 	 */
17404 	getCode: function () {
17405 		return this.code;
17406 	},
17407 	
17408 	/**
17409 	 * Return the default number of fraction digits that is typically used
17410 	 * with this type of currency.
17411 	 * @return {number} the number of fraction digits for this currency
17412 	 */
17413 	getFractionDigits: function () {
17414 		return this.fractionDigits;
17415 	},
17416 	
17417 	/**
17418 	 * Return the sign commonly used to represent this currency.
17419 	 * @return {string} the sign commonly used to represent this currency
17420 	 */
17421 	getSign: function () {
17422 		return this.sign;
17423 	},
17424 	
17425 	/**
17426 	 * Return the name of the currency in English.
17427 	 * @return {string} the name of the currency in English
17428 	 */
17429 	getName: function () {
17430 		return this.name;
17431 	},
17432 	
17433 	/**
17434 	 * Return the locale for this currency. If the options to the constructor 
17435 	 * included a locale property in order to find the currency that is appropriate
17436 	 * for that locale, then the locale is returned here. If the options did not
17437 	 * include a locale, then this method returns undefined.
17438 	 * @return {Locale} the locale used in the constructor of this instance,
17439 	 * or undefined if no locale was given in the constructor
17440 	 */
17441 	getLocale: function () {
17442 		return this.locale;
17443 	}
17444 };
17445 
17446 
17447 
17448 /*< INumber.js */
17449 /*
17450  * INumber.js - Parse a number in any locale
17451  * 
17452  * Copyright © 2012-2015, JEDLSoft
17453  *
17454  * Licensed under the Apache License, Version 2.0 (the "License");
17455  * you may not use this file except in compliance with the License.
17456  * You may obtain a copy of the License at
17457  *
17458  *     http://www.apache.org/licenses/LICENSE-2.0
17459  *
17460  * Unless required by applicable law or agreed to in writing, software
17461  * distributed under the License is distributed on an "AS IS" BASIS,
17462  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17463  *
17464  * See the License for the specific language governing permissions and
17465  * limitations under the License.
17466  */
17467 
17468 /*
17469 !depends 
17470 ilib.js 
17471 Locale.js 
17472 isDigit.js 
17473 isSpace.js
17474 LocaleInfo.js
17475 Utils.js
17476 Currency.js
17477 */
17478 
17479 
17480 
17481 
17482 
17483 
17484 /**
17485  * @class
17486  * Parse a string as a number, ignoring all locale-specific formatting.<p>
17487  * 
17488  * This class is different from the standard Javascript parseInt() and parseFloat() 
17489  * functions in that the number to be parsed can have formatting characters in it 
17490  * that are not supported by those two
17491  * functions, and it handles numbers written in other locales properly. For example, 
17492  * if you pass the string "203,231.23" to the parseFloat() function in Javascript, it 
17493  * will return you the number 203. The INumber class will parse it correctly and 
17494  * the value() function will return the number 203231.23. If you pass parseFloat() the 
17495  * string "203.231,23" with the locale set to de-DE, it will return you 203 again. This
17496  * class will return the correct number 203231.23 again.<p>
17497  * 
17498  * The options object may contain any of the following properties:
17499  * 
17500  * <ul>
17501  * <li><i>locale</i> - specify the locale of the string to parse. This is used to
17502  * figure out what the decimal point character is. If not specified, the default locale
17503  * for the app or browser is used.
17504  * <li><i>type</i> - specify whether this string should be interpretted as a number,
17505  * currency, or percentage amount. When the number is interpretted as a currency
17506  * amount, the getCurrency() method will return something useful, otherwise it will
17507  * return undefined. If
17508  * the number is to be interpretted as percentage amount and there is a percentage sign
17509  * in the string, then the number will be returned
17510  * as a fraction from the valueOf() method. If there is no percentage sign, then the 
17511  * number will be returned as a regular number. That is "58.3%" will be returned as the 
17512  * number 0.583 but "58.3" will be returned as 58.3. Valid values for this property 
17513  * are "number", "currency", and "percentage". Default if this is not specified is
17514  * "number".
17515  * <li><i>onLoad</i> - a callback function to call when the locale data is fully 
17516  * loaded. When the onLoad option is given, this class will attempt to
17517  * load any missing locale data using the ilib loader callback.
17518  * When the constructor is done (even if the data is already preassembled), the 
17519  * onLoad function is called with the current instance as a parameter, so this
17520  * callback can be used with preassembled or dynamic loading or a mix of the two. 
17521  * 
17522  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
17523  * asynchronously. If this option is given as "false", then the "onLoad"
17524  * callback must be given, as the instance returned from this constructor will
17525  * not be usable for a while.
17526  *  
17527  * <li><i>loadParams</i> - an object containing parameters to pass to the 
17528  * loader callback function when locale data is missing. The parameters are not
17529  * interpretted or modified in any way. They are simply passed along. The object 
17530  * may contain any property/value pairs as long as the calling code is in
17531  * agreement with the loader callback function as to what those parameters mean.
17532  * </ul>
17533  * <p>
17534  * 
17535  * This class is named INumber ("ilib number") so as not to conflict with the 
17536  * built-in Javascript Number class.
17537  * 
17538  * @constructor
17539  * @param {string|number|INumber|Number|undefined} str a string to parse as a number, or a number value
17540  * @param {Object=} options Options controlling how the instance should be created 
17541  */
17542 var INumber = function (str, options) {
17543 	var i, stripped = "", 
17544 		sync = true,
17545 		loadParams,
17546 		onLoad;
17547 	
17548 	this.locale = new Locale();
17549 	this.type = "number";
17550 	
17551 	if (options) {
17552 		if (options.locale) {
17553 			this.locale = (typeof(options.locale) === 'string') ? new Locale(options.locale) : options.locale;
17554 		}
17555 		if (options.type) {
17556 			switch (options.type) {
17557 				case "number":
17558 				case "currency":
17559 				case "percentage":
17560 					this.type = options.type;
17561 					break;
17562 				default:
17563 					break;
17564 			}
17565 		}
17566 		if (typeof(options.sync) !== 'undefined') {
17567 			sync = (options.sync == true);
17568 		}
17569 		loadParams = options.loadParams;
17570 		onLoad = options.onLoad;
17571 	}
17572 	
17573 	isDigit._init(sync, loadParams, ilib.bind(this, function() {
17574 		isSpace._init(sync, loadParams, ilib.bind(this, function() {
17575 			new LocaleInfo(this.locale, {
17576 				sync: sync,
17577 				onLoad: ilib.bind(this, function (li) {
17578 					this.decimal = li.getDecimalSeparator();
17579 					
17580 					switch (typeof(str)) {
17581 					case 'string':
17582 						// stripping should work for all locales, because you just ignore all the
17583 						// formatting except the decimal char
17584 						var unary = true; // looking for the unary minus still?
17585 						var lastNumericChar = 0;
17586 						this.str = str || "0";
17587 						i = 0;
17588 						for (i = 0; i < this.str.length; i++) {
17589 							if (unary && this.str.charAt(i) === '-') {
17590 								unary = false;
17591 								stripped += this.str.charAt(i);
17592 								lastNumericChar = i;
17593 							} else if (isDigit(this.str.charAt(i))) {
17594 								stripped += this.str.charAt(i);
17595 								unary = false;
17596 								lastNumericChar = i;
17597 							} else if (this.str.charAt(i) === this.decimal) {
17598 								stripped += "."; // always convert to period
17599 								unary = false;
17600 								lastNumericChar = i;
17601 							} // else ignore
17602 						}
17603 						// record what we actually parsed
17604 						this.parsed = this.str.substring(0, lastNumericChar+1);
17605 						/** @type {number} */
17606 						this.value = parseFloat(stripped);
17607 						break;
17608 					case 'number':
17609 						this.str = "" + str;
17610 						this.value = str;
17611 						break;
17612 						
17613 					case 'object':
17614 						// call parseFloat to coerse the type to number
17615 						this.value = parseFloat(str.valueOf());
17616     					this.str = "" + this.value;
17617 						break;
17618 						
17619 					case 'undefined':
17620 						this.value = 0;
17621 						this.str = "0";
17622 						break;
17623 					}
17624 					
17625 					switch (this.type) {
17626 						default:
17627 							// don't need to do anything special for other types
17628 							break;
17629 						case "percentage":
17630 							if (this.str.indexOf(li.getPercentageSymbol()) !== -1) {
17631 								this.value /= 100;
17632 							}
17633 							break;
17634 						case "currency":
17635 							stripped = "";
17636 							i = 0;
17637 							while (i < this.str.length &&
17638 								   !isDigit(this.str.charAt(i)) &&
17639 								   !isSpace(this.str.charAt(i))) {
17640 								stripped += this.str.charAt(i++);
17641 							}
17642 							if (stripped.length === 0) {
17643 								while (i < this.str.length && 
17644 									   isDigit(this.str.charAt(i)) ||
17645 									   isSpace(this.str.charAt(i)) ||
17646 									   this.str.charAt(i) === '.' ||
17647 									   this.str.charAt(i) === ',' ) {
17648 									i++;
17649 								}
17650 								while (i < this.str.length && 
17651 									   !isDigit(this.str.charAt(i)) &&
17652 									   !isSpace(this.str.charAt(i))) {
17653 									stripped += this.str.charAt(i++);
17654 								}
17655 							}
17656 							new Currency({
17657 								locale: this.locale, 
17658 								sign: stripped,
17659 								sync: sync,
17660 								onLoad: ilib.bind(this, function (cur) {
17661 									this.currency = cur;
17662 									if (options && typeof(options.onLoad) === 'function') {
17663 										options.onLoad(this);
17664 									}				
17665 								})
17666 							});
17667 							return;
17668 					}
17669 					
17670 					if (options && typeof(options.onLoad) === 'function') {
17671 						options.onLoad(this);
17672 					}
17673 				})
17674 			});
17675 		}));
17676 	}));
17677 };
17678 
17679 INumber.prototype = {
17680 	/**
17681 	 * Return the locale for this formatter instance.
17682 	 * @return {Locale} the locale instance for this formatter
17683 	 */
17684 	getLocale: function () {
17685 		return this.locale;
17686 	},
17687 	
17688 	/**
17689 	 * Return the original string that this number instance was created with.
17690 	 * @return {string} the original string
17691 	 */
17692 	toString: function () {
17693 		return this.str;
17694 	},
17695 	
17696 	/**
17697 	 * If the type of this INumber instance is "currency", then the parser will attempt
17698 	 * to figure out which currency this amount represents. The amount can be written
17699 	 * with any of the currency signs or ISO 4217 codes that are currently
17700 	 * recognized by ilib, and the currency signs may occur before or after the
17701 	 * numeric portion of the string. If no currency can be recognized, then the 
17702 	 * default currency for the locale is returned. If multiple currencies can be
17703 	 * recognized (for example if the currency sign is "$"), then this method 
17704 	 * will prefer the one for the current locale. If multiple currencies can be
17705 	 * recognized, but none are used in the current locale, then the first currency
17706 	 * encountered will be used. This may produce random results, though the larger
17707 	 * currencies occur earlier in the list. For example, if the sign found in the
17708 	 * string is "$" and that is not the sign of the currency of the current locale
17709 	 * then the US dollar will be recognized, as it is the largest currency that uses
17710 	 * the "$" as its sign.
17711 	 * 
17712 	 * @return {Currency|undefined} the currency instance for this amount, or 
17713 	 * undefined if this INumber object is not of type currency
17714 	 */
17715 	getCurrency: function () {
17716 		return this.currency;
17717 	},
17718 	
17719 	/**
17720 	 * Return the value of this INumber object as a primitive number instance.
17721 	 * @return {number} the value of this number instance
17722 	 */
17723 	valueOf: function () {
17724 		return this.value;
17725 	}
17726 };
17727 
17728 
17729 /*< NumFmt.js */
17730 /*
17731  * NumFmt.js - Number formatter definition
17732  *
17733  * Copyright © 2012-2015, JEDLSoft
17734  *
17735  * Licensed under the Apache License, Version 2.0 (the "License");
17736  * you may not use this file except in compliance with the License.
17737  * You may obtain a copy of the License at
17738  *
17739  *     http://www.apache.org/licenses/LICENSE-2.0
17740  *
17741  * Unless required by applicable law or agreed to in writing, software
17742  * distributed under the License is distributed on an "AS IS" BASIS,
17743  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17744  *
17745  * See the License for the specific language governing permissions and
17746  * limitations under the License.
17747  */
17748 
17749 /*
17750 !depends 
17751 ilib.js 
17752 Locale.js
17753 LocaleInfo.js
17754 Utils.js
17755 MathUtils.js
17756 Currency.js
17757 IString.js
17758 JSUtils.js
17759 INumber.js
17760 */
17761 
17762 // !data localeinfo currency
17763 
17764 
17765 
17766 /**
17767  * @class
17768  * Create a new number formatter instance. Locales differ in the way that digits
17769  * in a formatted number are grouped, in the way the decimal character is represented,
17770  * etc. Use this formatter to get it right for any locale.<p>
17771  *
17772  * This formatter can format plain numbers, currency amounts, and percentage amounts.<p>
17773  *
17774  * As with all formatters, the recommended
17775  * practice is to create one formatter and use it multiple times to format various
17776  * numbers.<p>
17777  *
17778  * The options can contain any of the following properties:
17779  *
17780  * <ul>
17781  * <li><i>locale</i> - use the conventions of the specified locale when figuring out how to
17782  * format a number.
17783  * <li><i>type</i> - the type of this formatter. Valid values are "number", "currency", or
17784  * "percentage". If this property is not specified, the default is "number".
17785  * <li><i>currency</i> - the ISO 4217 3-letter currency code to use when the formatter type
17786  * is "currency". This property is required for currency formatting. If the type property
17787  * is "currency" and the currency property is not specified, the constructor will throw a
17788  * an exception.
17789  * <li><i>maxFractionDigits</i> - the maximum number of digits that should appear in the
17790  * formatted output after the decimal. A value of -1 means unlimited, and 0 means only print
17791  * the integral part of the number.
17792  * <li><i>minFractionDigits</i> - the minimum number of fractional digits that should
17793  * appear in the formatted output. If the number does not have enough fractional digits
17794  * to reach this minimum, the number will be zero-padded at the end to get to the limit.
17795  * If the type of the formatter is "currency" and this
17796  * property is not specified, then the minimum fraction digits is set to the normal number
17797  * of digits used with that currency, which is almost always 0, 2, or 3 digits.
17798  * <li><i>useNative</i> - the flag used to determaine whether to use the native script settings
17799  * for formatting the numbers .
17800  * <li><i>roundingMode</i> - When the maxFractionDigits or maxIntegerDigits is specified,
17801  * this property governs how the least significant digits are rounded to conform to that
17802  * maximum. The value of this property is a string with one of the following values:
17803  * <ul>
17804  *   <li><i>up</i> - round away from zero
17805  *   <li><i>down</i> - round towards zero. This has the effect of truncating the number
17806  *   <li><i>ceiling</i> - round towards positive infinity
17807  *   <li><i>floor</i> - round towards negative infinity
17808  *   <li><i>halfup</i> - round towards nearest neighbour. If equidistant, round up.
17809  *   <li><i>halfdown</i> - round towards nearest neighbour. If equidistant, round down.
17810  *   <li><i>halfeven</i> - round towards nearest neighbour. If equidistant, round towards the even neighbour
17811  *   <li><i>halfodd</i> - round towards nearest neighbour. If equidistant, round towards the odd neighbour
17812  * </ul>
17813  * When the type of the formatter is "currency" and the <i>roundingMode</i> property is not
17814  * set, then the standard legal rounding rules for the locale are followed. If the type
17815  * is "number" or "percentage" and the <i>roundingMode</i> property is not set, then the
17816  * default mode is "halfdown".</i>.
17817  *
17818  * <li><i>style</i> - When the type of this formatter is "currency", the currency amount
17819  * can be formatted in the following styles: "common" and "iso". The common style is the
17820  * one commonly used in every day writing where the currency unit is represented using a
17821  * symbol. eg. "$57.35" for fifty-seven dollars and thirty five cents. The iso style is
17822  * the international style where the currency unit is represented using the ISO 4217 code.
17823  * eg. "USD 57.35" for the same amount. The default is "common" style if the style is
17824  * not specified.<p>
17825  *
17826  * When the type of this formatter is "number", the style can be one of the following:
17827  * <ul>
17828  *   <li><i>standard - format a fully specified floating point number properly for the locale
17829  *   <li><i>scientific</i> - use scientific notation for all numbers. That is, 1 integral 
17830  *   digit, followed by a number of fractional digits, followed by an "e" which denotes 
17831  *   exponentiation, followed digits which give the power of 10 in the exponent. 
17832  *   <li><i>native</i> - format a floating point number using the native digits and 
17833  *   formatting symbols for the script of the locale. 
17834  *   <li><i>nogrouping</i> - format a floating point number without grouping digits for
17835  *   the integral portion of the number
17836  * </ul>
17837  * Note that if you specify a maximum number
17838  * of integral digits, the formatter with a standard style will give you standard
17839  * formatting for smaller numbers and scientific notation for larger numbers. The default
17840  * is standard style if this is not specified.
17841  *
17842  * <li><i>onLoad</i> - a callback function to call when the format data is fully
17843  * loaded. When the onLoad option is given, this class will attempt to
17844  * load any missing locale data using the ilib loader callback.
17845  * When the constructor is done (even if the data is already preassembled), the
17846  * onLoad function is called with the current instance as a parameter, so this
17847  * callback can be used with preassembled or dynamic loading or a mix of the two.
17848  *
17849  * <li>sync - tell whether to load any missing locale data synchronously or
17850  * asynchronously. If this option is given as "false", then the "onLoad"
17851  * callback must be given, as the instance returned from this constructor will
17852  * not be usable for a while.
17853  *
17854  * <li><i>loadParams</i> - an object containing parameters to pass to the
17855  * loader callback function when locale data is missing. The parameters are not
17856  * interpretted or modified in any way. They are simply passed along. The object
17857  * may contain any property/value pairs as long as the calling code is in
17858  * agreement with the loader callback function as to what those parameters mean.
17859  * </ul>
17860  * <p>
17861  *
17862  *
17863  * @constructor
17864  * @param {Object.<string,*>} options A set of options that govern how the formatter will behave
17865  */
17866 var NumFmt = function (options) {
17867 	var sync = true;
17868 	this.locale = new Locale();
17869 	/** 
17870 	 * @private
17871 	 * @type {string} 
17872 	 */
17873 	this.type = "number";
17874 	var loadParams = undefined;
17875 
17876 	if (options) {
17877 		if (options.locale) {
17878 			this.locale = (typeof (options.locale) === 'string') ? new Locale(options.locale) : options.locale;
17879 		}
17880 
17881 		if (options.type) {
17882 			if (options.type === 'number' ||
17883 				options.type === 'currency' ||
17884 				options.type === 'percentage') {
17885 				this.type = options.type;
17886 			}
17887 		}
17888 
17889 		if (options.currency) {
17890 			/** 
17891 			 * @private 
17892 			 * @type {string} 
17893 			 */
17894 			this.currency = options.currency;
17895 		}
17896 
17897 		if (typeof (options.maxFractionDigits) === 'number') {
17898 			/** 
17899 			 * @private 
17900 			 * @type {number|undefined} 
17901 			 */
17902 			this.maxFractionDigits = this._toPrimitive(options.maxFractionDigits);
17903 		}
17904 		if (typeof (options.minFractionDigits) === 'number') {
17905 			/** 
17906 			 * @private 
17907 			 * @type {number|undefined} 
17908 			 */
17909 			this.minFractionDigits = this._toPrimitive(options.minFractionDigits);
17910 			// enforce the limits to avoid JS exceptions
17911 			if (this.minFractionDigits < 0) {
17912 				this.minFractionDigits = 0;
17913 			}
17914 			if (this.minFractionDigits > 20) {
17915 				this.minFractionDigits = 20;
17916 			}
17917 		}
17918 		if (options.style) {
17919 			/** 
17920 			 * @private 
17921 			 * @type {string} 
17922 			 */
17923 			this.style = options.style;
17924 		}
17925 		if (typeof(options.useNative) === 'boolean') {
17926 			/** 
17927 			 * @private 
17928 			 * @type {boolean} 
17929 			 * */
17930 			this.useNative = options.useNative;
17931 		}
17932 		/** 
17933 		 * @private 
17934 		 * @type {string} 
17935 		 */
17936 		this.roundingMode = options.roundingMode;
17937 
17938 		if (typeof(options.sync) === 'boolean') {
17939 			sync = options.sync;
17940 		}
17941 		
17942 		loadParams = options.loadParams;
17943 	}
17944 
17945 	/** 
17946 	 * @private 
17947 	 * @type {LocaleInfo|undefined} 
17948 	 */
17949 	this.localeInfo = undefined;
17950 	
17951 	new LocaleInfo(this.locale, {
17952 		sync: sync,
17953 		loadParams: loadParams,
17954 		onLoad: ilib.bind(this, function (li) {
17955 			/** 
17956 			 * @private 
17957 			 * @type {LocaleInfo|undefined} 
17958 			 */
17959 			this.localeInfo = li;
17960 
17961 			if (this.type === "number") {
17962 				this.templateNegative = new IString(this.localeInfo.getNegativeNumberFormat() || "-{n}");
17963 			} else if (this.type === "currency") {
17964 				var templates;
17965 
17966 				if (!this.currency || typeof (this.currency) != 'string') {
17967 					throw "A currency property is required in the options to the number formatter constructor when the type property is set to currency.";
17968 				}
17969 
17970 				new Currency({
17971 					locale: this.locale,
17972 					code: this.currency,
17973 					sync: sync,
17974 					loadParams: loadParams,
17975 					onLoad: ilib.bind(this, function (cur) {
17976 						this.currencyInfo = cur;
17977 						if (this.style !== "common" && this.style !== "iso") {
17978 							this.style = "common";
17979 						}
17980 						
17981 						if (typeof(this.maxFractionDigits) !== 'number' && typeof(this.minFractionDigits) !== 'number') {
17982 							this.minFractionDigits = this.maxFractionDigits = this.currencyInfo.getFractionDigits();
17983 						}
17984 
17985 						templates = this.localeInfo.getCurrencyFormats();
17986 						this.template = new IString(templates[this.style] || templates.common);
17987 						this.templateNegative = new IString(templates[this.style + "Negative"] || templates["commonNegative"]);
17988 						this.sign = (this.style === "iso") ? this.currencyInfo.getCode() : this.currencyInfo.getSign();
17989 						
17990 						if (!this.roundingMode) {
17991 							this.roundingMode = this.currencyInfo && this.currencyInfo.roundingMode;
17992 						}
17993 
17994 						this._init();
17995 
17996 						if (options && typeof (options.onLoad) === 'function') {
17997 							options.onLoad(this);
17998 						}
17999 					})
18000 				});
18001 				return;
18002 			} else if (this.type === "percentage") {
18003 				this.template =  new IString(this.localeInfo.getPercentageFormat() || "{n}%");
18004 				this.templateNegative = new IString(this.localeInfo.getNegativePercentageFormat() || this.localeInfo.getNegativeNumberFormat() + "%");
18005 			}
18006 
18007 			this._init();
18008 
18009 			if (options && typeof (options.onLoad) === 'function') {
18010 				options.onLoad(this);
18011 			}
18012 		})
18013 	});
18014 };
18015 
18016 /**
18017  * Return an array of available locales that this formatter can format
18018  * @static
18019  * @return {Array.<Locale>|undefined} an array of available locales
18020  */
18021 NumFmt.getAvailableLocales = function () {
18022 	return undefined;
18023 };
18024 
18025 /**
18026  * @private
18027  * @const
18028  * @type string
18029  */
18030 NumFmt.zeros = "0000000000000000000000000000000000000000000000000000000000000000000000";
18031 
18032 NumFmt.prototype = {
18033 	/**
18034 	 * Return true if this formatter uses native digits to format the number. If the useNative
18035 	 * option is given to the constructor, then this flag will be honoured. If the useNative
18036 	 * option is not given to the constructor, this this formatter will use native digits if
18037 	 * the locale typically uses native digits.
18038 	 * 
18039 	 *  @return {boolean} true if this formatter will format with native digits, false otherwise
18040 	 */
18041 	getUseNative: function() {
18042 		if (typeof(this.useNative) === "boolean") {
18043 			return this.useNative;
18044 		} 
18045 		return (this.localeInfo.getDigitsStyle() === "native");
18046 	},
18047 	
18048 	/**
18049 	 * @private
18050 	 */
18051 	_init: function () {
18052 		if (this.maxFractionDigits < this.minFractionDigits) {
18053 			this.minFractionDigits = this.maxFractionDigits;
18054 		}
18055 
18056 		if (!this.roundingMode) {
18057 			this.roundingMode = this.localeInfo.getRoundingMode();
18058 		}
18059 
18060 		if (!this.roundingMode) {
18061 			this.roundingMode = "halfdown";
18062 		}
18063 
18064 		// set up the function, so we only have to figure it out once
18065 		// and not every time we do format()
18066 		this.round = MathUtils[this.roundingMode];
18067 		if (!this.round) {
18068 			this.roundingMode = "halfdown";
18069 			this.round = MathUtils[this.roundingMode];
18070 		}
18071 		
18072 		if (this.style === "nogrouping") {
18073 			this.prigroupSize = this.secgroupSize = 0;
18074 		} else {
18075 			this.prigroupSize = this.localeInfo.getPrimaryGroupingDigits();
18076 			this.secgroupSize = this.localeInfo.getSecondaryGroupingDigits();
18077 			this.groupingSeparator = this.getUseNative() ? this.localeInfo.getNativeGroupingSeparator() : this.localeInfo.getGroupingSeparator();
18078 		} 
18079 		this.decimalSeparator = this.getUseNative() ? this.localeInfo.getNativeDecimalSeparator() : this.localeInfo.getDecimalSeparator();
18080 		
18081 		if (this.getUseNative()) {
18082 			var nd = this.localeInfo.getNativeDigits() || this.localeInfo.getDigits();
18083 			if (nd) {
18084 				this.digits = nd.split("");
18085 			}
18086 		}
18087 		
18088 		this.exponentSymbol = this.localeInfo.getExponential() || "e";
18089 	},
18090 
18091 	/**
18092 	 * @private
18093 	 * @param {INumber|Number|string|number} num object, string, or number to convert to a primitive number
18094 	 * @return {number} the primitive number equivalent of the argument
18095 	 */
18096 	_toPrimitive: function (num) {
18097 		var n = 0;
18098 
18099 		switch (typeof (num)) {
18100 		case 'number':
18101 			n = num;
18102 			break;
18103 		case 'string':
18104 			n = parseFloat(num);
18105 			break;
18106 		case 'object':
18107 			// call parseFloat to coerse the type to number 
18108 			n = parseFloat(num.valueOf());
18109 			break;
18110 		}
18111 
18112 		return n;
18113 	},
18114 
18115 	/**
18116 	 * Format the number using scientific notation as a positive number. Negative
18117 	 * formatting to be applied later.
18118 	 * @private
18119 	 * @param {number} num the number to format
18120 	 * @return {string} the formatted number
18121 	 */
18122 	_formatScientific: function (num) {
18123 		var n = new Number(num);
18124 		var formatted;
18125 		
18126 		var factor,
18127 			str = n.toExponential(),
18128 			parts = str.split("e"),
18129 			significant = parts[0],
18130 			exponent = parts[1],
18131 			numparts,
18132 			integral,
18133 			fraction;
18134 
18135 		if (this.maxFractionDigits > 0) {
18136 			// if there is a max fraction digits setting, round the fraction to 
18137 			// the right length first by dividing or multiplying by powers of 10. 
18138 			// manipulate the fraction digits so as to
18139 			// avoid the rounding errors of floating point numbers
18140 			factor = Math.pow(10, this.maxFractionDigits);
18141 			significant = this.round(significant * factor) / factor;
18142 		}
18143 		numparts = ("" + significant).split(".");
18144 		integral = numparts[0];
18145 		fraction = numparts[1];
18146 		
18147 		if (typeof(this.maxFractionDigits) !== 'undefined') {
18148 			fraction = fraction.substring(0, this.maxFractionDigits);
18149 		}
18150 		if (typeof(this.minFractionDigits) !== 'undefined') {
18151 			fraction = JSUtils.pad(fraction || "", this.minFractionDigits, true);
18152 		}
18153 		formatted = integral;
18154 		if (fraction.length) {
18155 			formatted += this.decimalSeparator + fraction;	
18156 		} 
18157 		formatted += this.exponentSymbol + exponent;
18158 		return formatted;
18159 	},
18160 
18161 	/**
18162 	 * Formats the number as a positive number. Negative formatting to be applied later.
18163 	 * @private
18164 	 * @param {number} num the number to format
18165 	 * @return {string} the formatted number
18166 	 */
18167 	_formatStandard: function (num) {
18168 		var i;
18169 		var k;
18170 		
18171 		if (typeof(this.maxFractionDigits) !== 'undefined' && this.maxFractionDigits > -1) {
18172 			var factor = Math.pow(10, this.maxFractionDigits);
18173 			num = this.round(num * factor) / factor;
18174 		}
18175 
18176 		num = Math.abs(num);
18177 
18178 		var parts = ("" + num).split("."),
18179 			integral = parts[0],
18180 			fraction = parts[1],
18181 			cycle,
18182 			formatted;
18183 		
18184 		integral = integral.toString();
18185 
18186 		if (this.minFractionDigits > 0) {
18187 			fraction = JSUtils.pad(fraction || "", this.minFractionDigits, true);
18188 		}
18189 
18190 		if (this.secgroupSize > 0) {
18191 			if (integral.length > this.prigroupSize) {
18192 				var size1 = this.prigroupSize;
18193 				var size2 = integral.length;
18194 				var size3 = size2 - size1;
18195 				integral = integral.slice(0, size3) + this.groupingSeparator + integral.slice(size3);
18196 				var num_sec = integral.substring(0, integral.indexOf(this.groupingSeparator));
18197 				k = num_sec.length;
18198 				while (k > this.secgroupSize) {
18199 					var secsize1 = this.secgroupSize;
18200 					var secsize2 = num_sec.length;
18201 					var secsize3 = secsize2 - secsize1;
18202 					integral = integral.slice(0, secsize3) + this.groupingSeparator + integral.slice(secsize3);
18203 					num_sec = integral.substring(0, integral.indexOf(this.groupingSeparator));
18204 					k = num_sec.length;
18205 				}
18206 			}
18207 
18208 			formatted = integral;
18209 		} else if (this.prigroupSize !== 0) {
18210 			cycle = MathUtils.mod(integral.length - 1, this.prigroupSize);
18211 
18212 			formatted = "";
18213 
18214 			for (i = 0; i < integral.length - 1; i++) {
18215 				formatted += integral.charAt(i);
18216 				if (cycle === 0) {
18217 					formatted += this.groupingSeparator;
18218 				}
18219 				cycle = MathUtils.mod(cycle - 1, this.prigroupSize);
18220 			}
18221 			formatted += integral.charAt(integral.length - 1);
18222 		} else {
18223 			formatted = integral;
18224 		}
18225 
18226 		if (fraction && (typeof(this.maxFractionDigits) === 'undefined' || this.maxFractionDigits > 0)) {
18227 			formatted += this.decimalSeparator;
18228 			formatted += fraction;
18229 		}
18230 		
18231 		if (this.digits) {
18232 			formatted = JSUtils.mapString(formatted, this.digits);
18233 		}
18234 		
18235 		return formatted;
18236 	},
18237 
18238 	/**
18239 	 * Format a number according to the settings of this number formatter instance.
18240 	 * @param num {number|string|INumber|Number} a floating point number to format
18241 	 * @return {string} a string containing the formatted number
18242 	 */
18243 	format: function (num) {
18244 		var formatted, n;
18245 
18246 		if (typeof (num) === 'undefined') {
18247 			return "";
18248 		}
18249 
18250 		// convert to a real primitive number type
18251 		n = this._toPrimitive(num);
18252 
18253 		if (this.type === "number") {
18254 			formatted = (this.style === "scientific") ?
18255 				this._formatScientific(n) :
18256 				this._formatStandard(n);
18257 
18258 			if (num < 0) {
18259 				formatted = this.templateNegative.format({n: formatted});
18260 			}
18261 		} else {
18262 			formatted = this._formatStandard(n);
18263 			var template = (n < 0) ? this.templateNegative : this.template;
18264 			formatted = template.format({
18265 				n: formatted,
18266 				s: this.sign
18267 			});
18268 		}
18269 
18270 		return formatted;
18271 	},
18272 
18273 	/**
18274 	 * Return the type of formatter. Valid values are "number", "currency", and
18275 	 * "percentage".
18276 	 *
18277 	 * @return {string} the type of formatter
18278 	 */
18279 	getType: function () {
18280 		return this.type;
18281 	},
18282 
18283 	/**
18284 	 * Return the locale for this formatter instance.
18285 	 * @return {Locale} the locale instance for this formatter
18286 	 */
18287 	getLocale: function () {
18288 		return this.locale;
18289 	},
18290 
18291 	/**
18292 	 * Returns true if this formatter groups together digits in the integral
18293 	 * portion of a number, based on the options set up in the constructor. In
18294 	 * most western European cultures, this means separating every 3 digits
18295 	 * of the integral portion of a number with a particular character.
18296 	 *
18297 	 * @return {boolean} true if this formatter groups digits in the integral
18298 	 * portion of the number
18299 	 */
18300 	isGroupingUsed: function () {
18301 		return (this.groupingSeparator !== 'undefined' && this.groupingSeparator.length > 0);
18302 	},
18303 
18304 	/**
18305 	 * Returns the maximum fraction digits set up in the constructor.
18306 	 *
18307 	 * @return {number} the maximum number of fractional digits this
18308 	 * formatter will format, or -1 for no maximum
18309 	 */
18310 	getMaxFractionDigits: function () {
18311 		return typeof (this.maxFractionDigits) !== 'undefined' ? this.maxFractionDigits : -1;
18312 	},
18313 
18314 	/**
18315 	 * Returns the minimum fraction digits set up in the constructor. If
18316 	 * the formatter has the type "currency", then the minimum fraction
18317 	 * digits is the amount of digits that is standard for the currency
18318 	 * in question unless overridden in the options to the constructor.
18319 	 *
18320 	 * @return {number} the minimum number of fractional digits this
18321 	 * formatter will format, or -1 for no minimum
18322 	 */
18323 	getMinFractionDigits: function () {
18324 		return typeof (this.minFractionDigits) !== 'undefined' ? this.minFractionDigits : -1;
18325 	},
18326 
18327 	/**
18328 	 * Returns the ISO 4217 code for the currency that this formatter formats.
18329 	 * IF the typeof this formatter is not "currency", then this method will
18330 	 * return undefined.
18331 	 *
18332 	 * @return {string} the ISO 4217 code for the currency that this formatter
18333 	 * formats, or undefined if this not a currency formatter
18334 	 */
18335 	getCurrency: function () {
18336 		return this.currencyInfo && this.currencyInfo.getCode();
18337 	},
18338 
18339 	/**
18340 	 * Returns the rounding mode set up in the constructor. The rounding mode
18341 	 * controls how numbers are rounded when the integral or fraction digits
18342 	 * of a number are limited.
18343 	 *
18344 	 * @return {string} the name of the rounding mode used in this formatter
18345 	 */
18346 	getRoundingMode: function () {
18347 		return this.roundingMode;
18348 	},
18349 
18350 	/**
18351 	 * If this formatter is a currency formatter, then the style determines how the
18352 	 * currency is denoted in the formatted output. This method returns the style
18353 	 * that this formatter will produce. (See the constructor comment for more about
18354 	 * the styles.)
18355 	 * @return {string} the name of the style this formatter will use to format
18356 	 * currency amounts, or "undefined" if this formatter is not a currency formatter
18357 	 */
18358 	getStyle: function () {
18359 		return this.style;
18360 	}
18361 };
18362 
18363 
18364 /*< DurationFmt.js */
18365 /*
18366  * DurFmt.js - Date formatter definition
18367  * 
18368  * Copyright © 2012-2015, JEDLSoft
18369  *
18370  * Licensed under the Apache License, Version 2.0 (the "License");
18371  * you may not use this file except in compliance with the License.
18372  * You may obtain a copy of the License at
18373  *
18374  *     http://www.apache.org/licenses/LICENSE-2.0
18375  *
18376  * Unless required by applicable law or agreed to in writing, software
18377  * distributed under the License is distributed on an "AS IS" BASIS,
18378  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18379  *
18380  * See the License for the specific language governing permissions and
18381  * limitations under the License.
18382  */
18383 
18384 /*
18385 !depends 
18386 ilib.js 
18387 Locale.js 
18388 DateFmt.js
18389 IString.js 
18390 ResBundle.js 
18391 LocaleInfo.js
18392 JSUtils.js
18393 Utils.js
18394 */
18395 
18396 // !data dateformats sysres
18397 // !resbundle sysres
18398 
18399 
18400 /**
18401  * @class
18402  * Create a new duration formatter instance. The duration formatter is immutable once
18403  * it is created, but can format as many different durations as needed with the same
18404  * options. Create different duration formatter instances for different purposes
18405  * and then keep them cached for use later if you have more than one duration to
18406  * format.<p>
18407  * 
18408  * Duration formatters format lengths of time. The duration formatter is meant to format 
18409  * durations of such things as the length of a song or a movie or a meeting, or the 
18410  * current position in that song or movie while playing it. If you wish to format a 
18411  * period of time that has a specific start and end date/time, then use a
18412  * [DateRngFmt] instance instead and call its format method.<p>
18413  *  
18414  * The options may contain any of the following properties:
18415  * 
18416  * <ul>
18417  * <li><i>locale</i> - locale to use when formatting the duration. If the locale is
18418  * not specified, then the default locale of the app or web page will be used.
18419  * 
18420  * <li><i>length</i> - Specify the length of the format to use. The length is the approximate size of the 
18421  * formatted string.
18422  * 
18423  * <ul>
18424  * <li><i>short</i> - use a short representation of the duration. This is the most compact format possible for the locale. eg. 1y 1m 1w 1d 1:01:01
18425  * <li><i>medium</i> - use a medium length representation of the duration. This is a slightly longer format. eg. 1 yr 1 mo 1 wk 1 dy 1 hr 1 mi 1 se
18426  * <li><i>long</i> - use a long representation of the duration. This is a fully specified format, but some of the textual 
18427  * parts may still be abbreviated. eg. 1 yr 1 mo 1 wk 1 day 1 hr 1 min 1 sec
18428  * <li><i>full</i> - use a full representation of the duration. This is a fully specified format where all the textual 
18429  * parts are spelled out completely. eg. 1 year, 1 month, 1 week, 1 day, 1 hour, 1 minute and 1 second
18430  * </ul>
18431  * 
18432  * <li><i>style<i> - whether hours, minutes, and seconds should be formatted as a text string
18433  * or as a regular time as on a clock. eg. text is "1 hour, 15 minutes", whereas clock is "1:15:00". Valid
18434  * values for this property are "text" or "clock". Default if this property is not specified
18435  * is "text".
18436  * 
18437  *<li><i>useNative</i> - the flag used to determaine whether to use the native script settings 
18438  * for formatting the numbers .
18439  * 
18440  * <li><i>onLoad</i> - a callback function to call when the format data is fully 
18441  * loaded. When the onLoad option is given, this class will attempt to
18442  * load any missing locale data using the ilib loader callback.
18443  * When the constructor is done (even if the data is already preassembled), the 
18444  * onLoad function is called with the current instance as a parameter, so this
18445  * callback can be used with preassembled or dynamic loading or a mix of the two. 
18446  * 
18447  * <li>sync - tell whether to load any missing locale data synchronously or 
18448  * asynchronously. If this option is given as "false", then the "onLoad"
18449  * callback must be given, as the instance returned from this constructor will
18450  * not be usable for a while.
18451  *  
18452  * <li><i>loadParams</i> - an object containing parameters to pass to the 
18453  * loader callback function when locale data is missing. The parameters are not
18454  * interpretted or modified in any way. They are simply passed along. The object 
18455  * may contain any property/value pairs as long as the calling code is in
18456  * agreement with the loader callback function as to what those parameters mean.
18457  * </ul>
18458  * <p>
18459  * 
18460  * 
18461  * @constructor
18462  * @param {?Object} options options governing the way this date formatter instance works
18463  */
18464 var DurationFmt = function(options) {
18465 	var sync = true;
18466 	var loadParams = undefined;
18467 	
18468 	this.locale = new Locale();
18469 	this.length = "short";
18470 	this.style = "text";
18471 	
18472 	if (options) {
18473 		if (options.locale) {
18474 			this.locale = (typeof(options.locale) === 'string') ? new Locale(options.locale) : options.locale;
18475 		}
18476 		
18477 		if (options.length) {
18478 			if (options.length === 'short' ||
18479 				options.length === 'medium' ||
18480 				options.length === 'long' ||
18481 				options.length === 'full') {
18482 				this.length = options.length;
18483 			}
18484 		}
18485 		
18486 		if (options.style) {
18487 			if (options.style === 'text' || options.style === 'clock') {
18488 				this.style = options.style;
18489 			}
18490 		}
18491 		
18492 		if (typeof(options.sync) !== 'undefined') {
18493 			sync = (options.sync == true);
18494 		}
18495 		
18496 		if (typeof(options.useNative) === 'boolean') {
18497 			this.useNative = options.useNative;
18498 		}
18499 		
18500 		loadParams = options.loadParams;
18501 	}
18502 	
18503 	new ResBundle({
18504 		locale: this.locale,
18505 		name: "sysres",
18506 		sync: sync,
18507 		loadParams: loadParams,
18508 		onLoad: ilib.bind(this, function (sysres) {
18509 			switch (this.length) {
18510 				case 'short':
18511 					this.components = {
18512 						year: sysres.getString("#{num}y"),
18513 						month: sysres.getString("#{num}m", "durationShortMonths"),
18514 						week: sysres.getString("#{num}w"),
18515 						day: sysres.getString("#{num}d"),
18516 						hour: sysres.getString("#{num}h"),
18517 						minute: sysres.getString("#{num}m", "durationShortMinutes"),
18518 						second: sysres.getString("#{num}s"),
18519 						millisecond: sysres.getString("#{num}m", "durationShortMillis"),
18520 						separator: sysres.getString(" ", "separatorShort"),
18521 						finalSeparator: "" // not used at this length
18522 					};
18523 					break;
18524 					
18525 				case 'medium':
18526 					this.components = {
18527 						year: sysres.getString("1#1 yr|#{num} yrs", "durationMediumYears"),
18528 						month: sysres.getString("1#1 mo|#{num} mos"),
18529 						week: sysres.getString("1#1 wk|#{num} wks", "durationMediumWeeks"),
18530 						day: sysres.getString("1#1 dy|#{num} dys"),
18531 						hour: sysres.getString("1#1 hr|#{num} hrs", "durationMediumHours"),
18532 						minute: sysres.getString("1#1 mi|#{num} min"),
18533 						second: sysres.getString("1#1 se|#{num} sec"),
18534 						millisecond: sysres.getString("#{num} ms"),
18535 						separator: sysres.getString(" ", "separatorMedium"),
18536 						finalSeparator: "" // not used at this length
18537 					};
18538 					break;
18539 					
18540 				case 'long':
18541 					this.components = {
18542 						year: sysres.getString("1#1 yr|#{num} yrs"),
18543 						month: sysres.getString("1#1 mon|#{num} mons"),
18544 						week: sysres.getString("1#1 wk|#{num} wks"),
18545 						day: sysres.getString("1#1 day|#{num} days", "durationLongDays"),
18546 						hour: sysres.getString("1#1 hr|#{num} hrs"),
18547 						minute: sysres.getString("1#1 min|#{num} min"),
18548 						second: sysres.getString("1#1 sec|#{num} sec"),
18549 						millisecond: sysres.getString("#{num} ms"),
18550 						separator: sysres.getString(", ", "separatorLong"),
18551 						finalSeparator: "" // not used at this length
18552 					};
18553 					break;
18554 					
18555 				case 'full':
18556 					this.components = {
18557 						year: sysres.getString("1#1 year|#{num} years"),
18558 						month: sysres.getString("1#1 month|#{num} months"),
18559 						week: sysres.getString("1#1 week|#{num} weeks"),
18560 						day: sysres.getString("1#1 day|#{num} days"),
18561 						hour: sysres.getString("1#1 hour|#{num} hours"),
18562 						minute: sysres.getString("1#1 minute|#{num} minutes"),
18563 						second: sysres.getString("1#1 second|#{num} seconds"),
18564 						millisecond: sysres.getString("1#1 millisecond|#{num} milliseconds"),
18565 						separator: sysres.getString(", ", "separatorFull"),
18566 						finalSeparator: sysres.getString(" and ", "finalSeparatorFull")
18567 					};
18568 					break;
18569 			}
18570 			
18571 			if (this.style === 'clock') {
18572 				new DateFmt({
18573 					locale: this.locale,
18574 					calendar: "gregorian",
18575 					type: "time",
18576 					time: "ms",
18577 					sync: sync,
18578 					loadParams: loadParams,
18579 					useNative: this.useNative,
18580 					onLoad: ilib.bind(this, function (fmtMS) {
18581 						this.timeFmtMS = fmtMS;
18582 						new DateFmt({
18583 							locale: this.locale,
18584 							calendar: "gregorian",
18585 							type: "time",
18586 							time: "hm",
18587 							sync: sync,
18588 							loadParams: loadParams,
18589 							useNative: this.useNative,
18590 							onLoad: ilib.bind(this, function (fmtHM) {
18591 								this.timeFmtHM = fmtHM;		
18592 								new DateFmt({
18593 									locale: this.locale,
18594 									calendar: "gregorian",
18595 									type: "time",
18596 									time: "hms",
18597 									sync: sync,
18598 									loadParams: loadParams,
18599 									useNative: this.useNative,
18600 									onLoad: ilib.bind(this, function (fmtHMS) {
18601 										this.timeFmtHMS = fmtHMS;		
18602 
18603 										// munge with the template to make sure that the hours are not formatted mod 12
18604 										this.timeFmtHM.template = this.timeFmtHM.template.replace(/hh?/, 'H');
18605 										this.timeFmtHM.templateArr = this.timeFmtHM._tokenize(this.timeFmtHM.template);
18606 										this.timeFmtHMS.template = this.timeFmtHMS.template.replace(/hh?/, 'H');
18607 										this.timeFmtHMS.templateArr = this.timeFmtHMS._tokenize(this.timeFmtHMS.template);
18608 										
18609 										this._init(this.timeFmtHM.locinfo, options && options.onLoad);
18610 									})
18611 								});
18612 							})
18613 						});
18614 					})
18615 				});
18616 				return;
18617 			}
18618 
18619 			new LocaleInfo(this.locale, {
18620 				sync: sync,
18621 				loadParams: loadParams,
18622 				onLoad: ilib.bind(this, function (li) {
18623 					this._init(li, options && options.onLoad);
18624 				})
18625 			});
18626 		})
18627 	});
18628 };
18629 
18630 /**
18631  * @private
18632  * @static
18633  */
18634 DurationFmt.complist = {
18635 	"text": ["year", "month", "week", "day", "hour", "minute", "second", "millisecond"],
18636 	"clock": ["year", "month", "week", "day"]
18637 };
18638 
18639 /**
18640  * @private
18641  */
18642 DurationFmt.prototype._mapDigits = function(str) {
18643 	if (this.useNative && this.digits) {
18644 		return JSUtils.mapString(str.toString(), this.digits);
18645 	}
18646 	return str;
18647 };
18648 
18649 /**
18650  * @private
18651  * @param {LocaleInfo} locinfo
18652  * @param {function(DurationFmt)|undefined} onLoad
18653  */
18654 DurationFmt.prototype._init = function(locinfo, onLoad) {
18655 	var digits;
18656 	if (typeof(this.useNative) === 'boolean') {
18657 		// if the caller explicitly said to use native or not, honour that despite what the locale data says...
18658 		if (this.useNative) {
18659 			digits = locinfo.getNativeDigits();
18660 			if (digits) {
18661 				this.digits = digits;
18662 			}
18663 		}
18664 	} else if (locinfo.getDigitsStyle() === "native") {
18665 		// else if the locale usually uses native digits, then use them 
18666 		digits = locinfo.getNativeDigits();
18667 		if (digits) {
18668 			this.useNative = true;
18669 			this.digits = digits;
18670 		}
18671 	} // else use western digits always
18672 
18673 	if (typeof(onLoad) === 'function') {
18674 		onLoad(this);
18675 	}
18676 };
18677 
18678 /**
18679  * Format a duration according to the format template of this formatter instance.<p>
18680  * 
18681  * The components parameter should be an object that contains any or all of these 
18682  * numeric properties:
18683  * 
18684  * <ul>
18685  * <li>year
18686  * <li>month
18687  * <li>week
18688  * <li>day
18689  * <li>hour
18690  * <li>minute
18691  * <li>second
18692  * </ul>
18693  * <p>
18694  *
18695  * When a property is left out of the components parameter or has a value of 0, it will not
18696  * be formatted into the output string, except for times that include 0 minutes and 0 seconds.
18697  * 
18698  * This formatter will not ensure that numbers for each component property is within the
18699  * valid range for that component. This allows you to format durations that are longer
18700  * than normal range. For example, you could format a duration has being "33 hours" rather
18701  * than "1 day, 9 hours".
18702  * 
18703  * @param {Object} components date/time components to be formatted into a duration string
18704  * @return {IString} a string with the duration formatted according to the style and 
18705  * locale set up for this formatter instance. If the components parameter is empty or 
18706  * undefined, an empty string is returned.
18707  */
18708 DurationFmt.prototype.format = function (components) {
18709 	var i, list, temp, fmt, secondlast = true, str = "";
18710 	
18711 	list = DurationFmt.complist[this.style];
18712 	//for (i = 0; i < list.length; i++) {
18713 	for (i = list.length-1; i >= 0; i--) {
18714 		//console.log("Now dealing with " + list[i]);
18715 		if (typeof(components[list[i]]) !== 'undefined' && components[list[i]] != 0) {
18716 			if (str.length > 0) {
18717 				str = ((this.length === 'full' && secondlast) ? this.components.finalSeparator : this.components.separator) + str;
18718 				secondlast = false;
18719 			}
18720 			str = this.components[list[i]].formatChoice(components[list[i]], {num: this._mapDigits(components[list[i]])}) + str;
18721 		}
18722 	}
18723 
18724 	if (this.style === 'clock') {
18725 		if (typeof(components.hour) !== 'undefined') {
18726 			fmt = (typeof(components.second) !== 'undefined') ? this.timeFmtHMS : this.timeFmtHM;
18727 		} else {
18728 			fmt = this.timeFmtMS;
18729 		}
18730 				
18731 		if (str.length > 0) {
18732 			str += this.components.separator;
18733 		}
18734 		str += fmt._formatTemplate(components, fmt.templateArr);
18735 	}
18736 	
18737 	return new IString(str);
18738 };
18739 
18740 /**
18741  * Return the locale that was used to construct this duration formatter object. If the
18742  * locale was not given as parameter to the constructor, this method returns the default
18743  * locale of the system.
18744  * 
18745  * @return {Locale} locale that this duration formatter was constructed with
18746  */
18747 DurationFmt.prototype.getLocale = function () {
18748 	return this.locale;
18749 };
18750 
18751 /**
18752  * Return the length that was used to construct this duration formatter object. If the
18753  * length was not given as parameter to the constructor, this method returns the default
18754  * length. Valid values are "short", "medium", "long", and "full".
18755  * 
18756  * @return {string} length that this duration formatter was constructed with
18757  */
18758 DurationFmt.prototype.getLength = function () {
18759 	return this.length;
18760 };
18761 
18762 /**
18763  * Return the style that was used to construct this duration formatter object. Returns
18764  * one of "text" or "clock".
18765  * 
18766  * @return {string} style that this duration formatter was constructed with
18767  */
18768 DurationFmt.prototype.getStyle = function () {
18769 	return this.style;
18770 };
18771 
18772 
18773 /*< isAlpha.js */
18774 /*
18775  * ctype.islpha.js - Character type is alphabetic
18776  * 
18777  * Copyright © 2012-2015, JEDLSoft
18778  *
18779  * Licensed under the Apache License, Version 2.0 (the "License");
18780  * you may not use this file except in compliance with the License.
18781  * You may obtain a copy of the License at
18782  *
18783  *     http://www.apache.org/licenses/LICENSE-2.0
18784  *
18785  * Unless required by applicable law or agreed to in writing, software
18786  * distributed under the License is distributed on an "AS IS" BASIS,
18787  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18788  *
18789  * See the License for the specific language governing permissions and
18790  * limitations under the License.
18791  */
18792 
18793 // !depends CType.js IString.js ilib.js
18794 
18795 // !data ctype_l
18796 
18797 
18798 /**
18799  * Return whether or not the first character is alphabetic.<p>
18800  * 
18801  * @static
18802  * @param {string|IString|number} ch character or code point to examine
18803  * @return {boolean} true if the first character is alphabetic.
18804  */
18805 var isAlpha = function (ch) {
18806 	var num;
18807 	switch (typeof(ch)) {
18808 		case 'number':
18809 			num = ch;
18810 			break;
18811 		case 'string':
18812 			num = IString.toCodePoint(ch, 0);
18813 			break;
18814 		case 'undefined':
18815 			return false;
18816 		default:
18817 			num = ch._toCodePoint(0);
18818 			break;
18819 	}
18820 	return CType._inRange(num, 'Lu', ilib.data.ctype_l) ||
18821 		CType._inRange(num, 'Ll', ilib.data.ctype_l) ||
18822 		CType._inRange(num, 'Lt', ilib.data.ctype_l) ||
18823 		CType._inRange(num, 'Lm', ilib.data.ctype_l) ||
18824 		CType._inRange(num, 'Lo', ilib.data.ctype_l);
18825 };
18826 
18827 /**
18828  * @protected
18829  * @param {boolean} sync
18830  * @param {Object|undefined} loadParams
18831  * @param {function(*)|undefined} onLoad
18832  */
18833 isAlpha._init = function (sync, loadParams, onLoad) {
18834 	CType._load("ctype_l", sync, loadParams, onLoad);
18835 };
18836 
18837 
18838 /*< isAlnum.js */
18839 /*
18840  * isAlnum.js - Character type is alphanumeric
18841  * 
18842  * Copyright © 2012-2015, JEDLSoft
18843  *
18844  * Licensed under the Apache License, Version 2.0 (the "License");
18845  * you may not use this file except in compliance with the License.
18846  * You may obtain a copy of the License at
18847  *
18848  *     http://www.apache.org/licenses/LICENSE-2.0
18849  *
18850  * Unless required by applicable law or agreed to in writing, software
18851  * distributed under the License is distributed on an "AS IS" BASIS,
18852  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18853  *
18854  * See the License for the specific language governing permissions and
18855  * limitations under the License.
18856  */
18857 
18858 // !depends CType.js IString.js isAlpha.js isDigit.js
18859 
18860 
18861 /**
18862  * Return whether or not the first character is alphabetic or numeric.<p>
18863  * 
18864  * @static
18865  * @param {string|IString|number} ch character or code point to examine
18866  * @return {boolean} true if the first character is alphabetic or numeric
18867  */
18868 var isAlnum = function (ch) {
18869 	var num;
18870 	switch (typeof(ch)) {
18871 		case 'number':
18872 			num = ch;
18873 			break;
18874 		case 'string':
18875 			num = IString.toCodePoint(ch, 0);
18876 			break;
18877 		case 'undefined':
18878 			return false;
18879 		default:
18880 			num = ch._toCodePoint(0);
18881 			break;
18882 	}
18883 	return isAlpha(num) || isDigit(num);
18884 };
18885 
18886 /**
18887  * @protected
18888  * @param {boolean} sync
18889  * @param {Object|undefined} loadParams
18890  * @param {function(*)|undefined} onLoad
18891  */
18892 isAlnum._init = function (sync, loadParams, onLoad) {
18893 	isAlpha._init(sync, loadParams, function () {
18894 		isDigit._init(sync, loadParams, onLoad);
18895 	});
18896 };
18897 
18898 
18899 
18900 /*< isAscii.js */
18901 /*
18902  * isAscii.js - Character type is ASCII
18903  * 
18904  * Copyright © 2012-2015, JEDLSoft
18905  *
18906  * Licensed under the Apache License, Version 2.0 (the "License");
18907  * you may not use this file except in compliance with the License.
18908  * You may obtain a copy of the License at
18909  *
18910  *     http://www.apache.org/licenses/LICENSE-2.0
18911  *
18912  * Unless required by applicable law or agreed to in writing, software
18913  * distributed under the License is distributed on an "AS IS" BASIS,
18914  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18915  *
18916  * See the License for the specific language governing permissions and
18917  * limitations under the License.
18918  */
18919 
18920 // !depends CType.js IString.js ilib.js
18921 
18922 // !data ctype
18923 
18924 
18925 /**
18926  * Return whether or not the first character is in the ASCII range.<p>
18927  * 
18928  * @static
18929  * @param {string|IString|number} ch character or code point to examine
18930  * @return {boolean} true if the first character is in the ASCII range.
18931  */
18932 var isAscii = function (ch) {
18933 	var num;
18934 	switch (typeof(ch)) {
18935 		case 'number':
18936 			num = ch;
18937 			break;
18938 		case 'string':
18939 			num = IString.toCodePoint(ch, 0);
18940 			break;
18941 		case 'undefined':
18942 			return false;
18943 		default:
18944 			num = ch._toCodePoint(0);
18945 			break;
18946 	}
18947 	return CType._inRange(num, 'ascii', ilib.data.ctype);
18948 };
18949 
18950 /**
18951  * @protected
18952  * @param {boolean} sync
18953  * @param {Object|undefined} loadParams
18954  * @param {function(*)|undefined} onLoad
18955  */
18956 isAscii._init = function (sync, loadParams, onLoad) {
18957 	CType._init(sync, loadParams, onLoad);
18958 };
18959 
18960 
18961 /*< isBlank.js */
18962 /*
18963  * isBlank.js - Character type is blank
18964  * 
18965  * Copyright © 2012-2015, JEDLSoft
18966  *
18967  * Licensed under the Apache License, Version 2.0 (the "License");
18968  * you may not use this file except in compliance with the License.
18969  * You may obtain a copy of the License at
18970  *
18971  *     http://www.apache.org/licenses/LICENSE-2.0
18972  *
18973  * Unless required by applicable law or agreed to in writing, software
18974  * distributed under the License is distributed on an "AS IS" BASIS,
18975  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18976  *
18977  * See the License for the specific language governing permissions and
18978  * limitations under the License.
18979  */
18980 
18981 // !depends CType.js IString.js ilib.js
18982 
18983 // !data ctype
18984 
18985 
18986 /**
18987  * Return whether or not the first character is a blank character.<p>
18988  * 
18989  * @static
18990  * ie. a space or a tab.
18991  * @param {string|IString|number} ch character or code point to examine
18992  * @return {boolean} true if the first character is a blank character.
18993  */
18994 var isBlank = function (ch) {
18995 	var num;
18996 	switch (typeof(ch)) {
18997 		case 'number':
18998 			num = ch;
18999 			break;
19000 		case 'string':
19001 			num = IString.toCodePoint(ch, 0);
19002 			break;
19003 		case 'undefined':
19004 			return false;
19005 		default:
19006 			num = ch._toCodePoint(0);
19007 			break;
19008 	}
19009 	return CType._inRange(num, 'blank', ilib.data.ctype);
19010 };
19011 
19012 /**
19013  * @protected
19014  * @param {boolean} sync
19015  * @param {Object|undefined} loadParams
19016  * @param {function(*)|undefined} onLoad
19017  */
19018 isBlank._init = function (sync, loadParams, onLoad) {
19019 	CType._init(sync, loadParams, onLoad);
19020 };
19021 
19022 
19023 /*< isCntrl.js */
19024 /*
19025  * isCntrl.js - Character type is control character
19026  * 
19027  * Copyright © 2012-2015, JEDLSoft
19028  *
19029  * Licensed under the Apache License, Version 2.0 (the "License");
19030  * you may not use this file except in compliance with the License.
19031  * You may obtain a copy of the License at
19032  *
19033  *     http://www.apache.org/licenses/LICENSE-2.0
19034  *
19035  * Unless required by applicable law or agreed to in writing, software
19036  * distributed under the License is distributed on an "AS IS" BASIS,
19037  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19038  *
19039  * See the License for the specific language governing permissions and
19040  * limitations under the License.
19041  */
19042 
19043 // !depends CType.js IString.js ilib.js
19044 
19045 // !data ctype_c
19046 
19047 
19048 /**
19049  * Return whether or not the first character is a control character.<p>
19050  * 
19051  * @static
19052  * @param {string|IString|number} ch character or code point to examine
19053  * @return {boolean} true if the first character is a control character.
19054  */
19055 var isCntrl = function (ch) {
19056 	var num;
19057 	switch (typeof(ch)) {
19058 		case 'number':
19059 			num = ch;
19060 			break;
19061 		case 'string':
19062 			num = IString.toCodePoint(ch, 0);
19063 			break;
19064 		case 'undefined':
19065 			return false;
19066 		default:
19067 			num = ch._toCodePoint(0);
19068 			break;
19069 	}
19070 	return CType._inRange(num, 'Cc', ilib.data.ctype_c);
19071 };
19072 
19073 /**
19074  * @protected
19075  * @param {boolean} sync
19076  * @param {Object|undefined} loadParams
19077  * @param {function(*)|undefined} onLoad
19078  */
19079 isCntrl._init = function (sync, loadParams, onLoad) {
19080 	CType._load("ctype_c", sync, loadParams, onLoad);
19081 };
19082 
19083 
19084 /*< isGraph.js */
19085 /*
19086  * isGraph.js - Character type is graph char
19087  * 
19088  * Copyright © 2012-2015, JEDLSoft
19089  *
19090  * Licensed under the Apache License, Version 2.0 (the "License");
19091  * you may not use this file except in compliance with the License.
19092  * You may obtain a copy of the License at
19093  *
19094  *     http://www.apache.org/licenses/LICENSE-2.0
19095  *
19096  * Unless required by applicable law or agreed to in writing, software
19097  * distributed under the License is distributed on an "AS IS" BASIS,
19098  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19099  *
19100  * See the License for the specific language governing permissions and
19101  * limitations under the License.
19102  */
19103 
19104 // !depends IString.js isSpace.js isCntrl.js ilib.js
19105 
19106 
19107 /**
19108  * Return whether or not the first character is any printable character
19109  * other than space.<p>
19110  * 
19111  * @static
19112  * @param {string|IString|number} ch character or code point to examine
19113  * @return {boolean} true if the first character is any printable character
19114  * other than space. 
19115  */
19116 var isGraph = function (ch) {
19117 	var num;
19118 	switch (typeof(ch)) {
19119 		case 'number':
19120 			num = ch;
19121 			break;
19122 		case 'string':
19123 			num = IString.toCodePoint(ch, 0);
19124 			break;
19125 		case 'undefined':
19126 			return false;
19127 		default:
19128 			num = ch._toCodePoint(0);
19129 			break;
19130 	}
19131 	return typeof(ch) !== 'undefined' && ch.length > 0 && !isSpace(num) && !isCntrl(num);
19132 };
19133 
19134 /**
19135  * @protected
19136  * @param {boolean} sync
19137  * @param {Object|undefined} loadParams
19138  * @param {function(*)|undefined} onLoad
19139  */
19140 isGraph._init = function (sync, loadParams, onLoad) {
19141 	isSpace._init(sync, loadParams, function () {
19142 		isCntrl._init(sync, loadParams, onLoad);
19143 	});
19144 };
19145 
19146 
19147 
19148 /*< isIdeo.js */
19149 /*
19150  * CType.js - Character type definitions
19151  * 
19152  * Copyright © 2012-2015, JEDLSoft
19153  *
19154  * Licensed under the Apache License, Version 2.0 (the "License");
19155  * you may not use this file except in compliance with the License.
19156  * You may obtain a copy of the License at
19157  *
19158  *     http://www.apache.org/licenses/LICENSE-2.0
19159  *
19160  * Unless required by applicable law or agreed to in writing, software
19161  * distributed under the License is distributed on an "AS IS" BASIS,
19162  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19163  *
19164  * See the License for the specific language governing permissions and
19165  * limitations under the License.
19166  */
19167 
19168 // !depends CType.js IString.js
19169 
19170 // !data ctype
19171 
19172 
19173 /**
19174  * Return whether or not the first character is an ideographic character.<p>
19175  * 
19176  * @static
19177  * @param {string|IString|number} ch character or code point to examine
19178  * @return {boolean} true if the first character is an ideographic character.
19179  */
19180 var isIdeo = function (ch) {
19181 	var num;
19182 	switch (typeof(ch)) {
19183 		case 'number':
19184 			num = ch;
19185 			break;
19186 		case 'string':
19187 			num = IString.toCodePoint(ch, 0);
19188 			break;
19189 		case 'undefined':
19190 			return false;
19191 		default:
19192 			num = ch._toCodePoint(0);
19193 			break;
19194 	}
19195 
19196 	return CType._inRange(num, 'cjk', ilib.data.ctype) ||
19197 		CType._inRange(num, 'cjkradicals', ilib.data.ctype) ||
19198 		CType._inRange(num, 'enclosedcjk', ilib.data.ctype) ||
19199 		CType._inRange(num, 'cjkpunct', ilib.data.ctype) ||
19200 		CType._inRange(num, 'cjkcompatibility', ilib.data.ctype);
19201 };
19202 
19203 /**
19204  * @protected
19205  * @param {boolean} sync
19206  * @param {Object|undefined} loadParams
19207  * @param {function(*)|undefined} onLoad
19208  */
19209 isIdeo._init = function (sync, loadParams, onLoad) {
19210 	CType._init(sync, loadParams, onLoad);
19211 };
19212 
19213 
19214 /*< isLower.js */
19215 /*
19216  * isLower.js - Character type is lower case letter
19217  * 
19218  * Copyright © 2012-2015, JEDLSoft
19219  *
19220  * Licensed under the Apache License, Version 2.0 (the "License");
19221  * you may not use this file except in compliance with the License.
19222  * You may obtain a copy of the License at
19223  *
19224  *     http://www.apache.org/licenses/LICENSE-2.0
19225  *
19226  * Unless required by applicable law or agreed to in writing, software
19227  * distributed under the License is distributed on an "AS IS" BASIS,
19228  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19229  *
19230  * See the License for the specific language governing permissions and
19231  * limitations under the License.
19232  */
19233 
19234 // !depends CType.js IString.js
19235 
19236 // !data ctype_l
19237 
19238 
19239 
19240 /**
19241  * Return whether or not the first character is lower-case. For alphabetic
19242  * characters in scripts that do not make a distinction between upper- and 
19243  * lower-case, this function always returns true.<p>
19244  * 
19245  * @static
19246  * @param {string|IString|number} ch character or code point to examine
19247  * @return {boolean} true if the first character is lower-case.
19248  */
19249 var isLower = function (ch) {
19250 	var num;
19251 	switch (typeof(ch)) {
19252 		case 'number':
19253 			num = ch;
19254 			break;
19255 		case 'string':
19256 			num = IString.toCodePoint(ch, 0);
19257 			break;
19258 		case 'undefined':
19259 			return false;
19260 		default:
19261 			num = ch._toCodePoint(0);
19262 			break;
19263 	}
19264 
19265 	return CType._inRange(num, 'Ll', ilib.data.ctype_l);
19266 };
19267 
19268 /**
19269  * @protected
19270  * @param {boolean} sync
19271  * @param {Object|undefined} loadParams
19272  * @param {function(*)|undefined} onLoad
19273  */
19274 isLower._init = function (sync, loadParams, onLoad) {
19275 	CType._load("ctype_l", sync, loadParams, onLoad);
19276 };
19277 
19278 
19279 /*< isPrint.js */
19280 /*
19281  * isPrint.js - Character type is printable char
19282  * 
19283  * Copyright © 2012-2015, JEDLSoft
19284  *
19285  * Licensed under the Apache License, Version 2.0 (the "License");
19286  * you may not use this file except in compliance with the License.
19287  * You may obtain a copy of the License at
19288  *
19289  *     http://www.apache.org/licenses/LICENSE-2.0
19290  *
19291  * Unless required by applicable law or agreed to in writing, software
19292  * distributed under the License is distributed on an "AS IS" BASIS,
19293  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19294  *
19295  * See the License for the specific language governing permissions and
19296  * limitations under the License.
19297  */
19298 
19299 // !depends CType.js isCntrl.js
19300 
19301 
19302 /**
19303  * Return whether or not the first character is any printable character,
19304  * including space.<p>
19305  * 
19306  * @static
19307  * @param {string|IString|number} ch character or code point to examine
19308  * @return {boolean} true if the first character is printable.
19309  */
19310 var isPrint = function (ch) {
19311 	return typeof(ch) !== 'undefined' && ch.length > 0 && !isCntrl(ch);
19312 };
19313 
19314 /**
19315  * @protected
19316  * @param {boolean} sync
19317  * @param {Object|undefined} loadParams
19318  * @param {function(*)|undefined} onLoad
19319  */
19320 isPrint._init = function (sync, loadParams, onLoad) {
19321 	isCntrl._init(sync, loadParams, onLoad);
19322 };
19323 
19324 
19325 /*< isPunct.js */
19326 /*
19327  * isPunct.js - Character type is punctuation
19328  * 
19329  * Copyright © 2012-2015, JEDLSoft
19330  *
19331  * Licensed under the Apache License, Version 2.0 (the "License");
19332  * you may not use this file except in compliance with the License.
19333  * You may obtain a copy of the License at
19334  *
19335  *     http://www.apache.org/licenses/LICENSE-2.0
19336  *
19337  * Unless required by applicable law or agreed to in writing, software
19338  * distributed under the License is distributed on an "AS IS" BASIS,
19339  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19340  *
19341  * See the License for the specific language governing permissions and
19342  * limitations under the License.
19343  */
19344 
19345 // !depends CType.js IString.js
19346 
19347 // !data ctype_p
19348 
19349 
19350 
19351 /**
19352  * Return whether or not the first character is punctuation.<p>
19353  * 
19354  * @static
19355  * @param {string|IString|number} ch character or code point to examine
19356  * @return {boolean} true if the first character is punctuation.
19357  */
19358 var isPunct = function (ch) {
19359 	var num;
19360 	switch (typeof(ch)) {
19361 		case 'number':
19362 			num = ch;
19363 			break;
19364 		case 'string':
19365 			num = IString.toCodePoint(ch, 0);
19366 			break;
19367 		case 'undefined':
19368 			return false;
19369 		default:
19370 			num = ch._toCodePoint(0);
19371 			break;
19372 	}
19373 
19374 	return CType._inRange(num, 'Pd', ilib.data.ctype_p) ||
19375 		CType._inRange(num, 'Ps', ilib.data.ctype_p) ||
19376 		CType._inRange(num, 'Pe', ilib.data.ctype_p) ||
19377 		CType._inRange(num, 'Pc', ilib.data.ctype_p) ||
19378 		CType._inRange(num, 'Po', ilib.data.ctype_p) ||
19379 		CType._inRange(num, 'Pi', ilib.data.ctype_p) ||
19380 		CType._inRange(num, 'Pf', ilib.data.ctype_p);
19381 };
19382 
19383 /**
19384  * @protected
19385  * @param {boolean} sync
19386  * @param {Object|undefined} loadParams
19387  * @param {function(*)|undefined} onLoad
19388  */
19389 isPunct._init = function (sync, loadParams, onLoad) {
19390 	CType._load("ctype_p", sync, loadParams, onLoad);
19391 };
19392 
19393 
19394 
19395 /*< isUpper.js */
19396 /*
19397  * isUpper.js - Character type is upper-case letter
19398  * 
19399  * Copyright © 2012-2015, JEDLSoft
19400  *
19401  * Licensed under the Apache License, Version 2.0 (the "License");
19402  * you may not use this file except in compliance with the License.
19403  * You may obtain a copy of the License at
19404  *
19405  *     http://www.apache.org/licenses/LICENSE-2.0
19406  *
19407  * Unless required by applicable law or agreed to in writing, software
19408  * distributed under the License is distributed on an "AS IS" BASIS,
19409  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19410  *
19411  * See the License for the specific language governing permissions and
19412  * limitations under the License.
19413  */
19414 
19415 // !depends CType.js IString.js
19416 
19417 // !data ctype_l
19418 
19419 
19420 
19421 /**
19422  * Return whether or not the first character is upper-case. For alphabetic
19423  * characters in scripts that do not make a distinction between upper- and 
19424  * lower-case, this function always returns true.<p>
19425  * 
19426  * @static
19427  * @param {string|IString|number} ch character or code point to examine
19428  * @return {boolean} true if the first character is upper-case.
19429  */
19430 var isUpper = function (ch) {
19431 	var num;
19432 	switch (typeof(ch)) {
19433 		case 'number':
19434 			num = ch;
19435 			break;
19436 		case 'string':
19437 			num = IString.toCodePoint(ch, 0);
19438 			break;
19439 		case 'undefined':
19440 			return false;
19441 		default:
19442 			num = ch._toCodePoint(0);
19443 			break;
19444 	}
19445 
19446 	return CType._inRange(num, 'Lu', ilib.data.ctype_l);
19447 };
19448 
19449 /**
19450  * @protected
19451  * @param {boolean} sync
19452  * @param {Object|undefined} loadParams
19453  * @param {function(*)|undefined} onLoad
19454  */
19455 isUpper._init = function (sync, loadParams, onLoad) {
19456 	CType._load("ctype_l", sync, loadParams, onLoad);
19457 };
19458 
19459 
19460 /*< isXdigit.js */
19461 /*
19462  * isXdigit.js - Character type is hex digit
19463  * 
19464  * Copyright © 2012-2015, JEDLSoft
19465  *
19466  * Licensed under the Apache License, Version 2.0 (the "License");
19467  * you may not use this file except in compliance with the License.
19468  * You may obtain a copy of the License at
19469  *
19470  *     http://www.apache.org/licenses/LICENSE-2.0
19471  *
19472  * Unless required by applicable law or agreed to in writing, software
19473  * distributed under the License is distributed on an "AS IS" BASIS,
19474  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19475  *
19476  * See the License for the specific language governing permissions and
19477  * limitations under the License.
19478  */
19479 
19480 // !depends CType.js IString.js
19481 
19482 // !data ctype
19483 
19484 
19485 
19486 /**
19487  * Return whether or not the first character is a hexadecimal digit written
19488  * in the Latin script. (0-9 or A-F)<p>
19489  * 
19490  * @static
19491  * @param {string|IString|number} ch character or code point to examine
19492  * @return {boolean} true if the first character is a hexadecimal digit written
19493  * in the Latin script.
19494  */
19495 var isXdigit = function (ch) {
19496 	var num;
19497 	switch (typeof(ch)) {
19498 		case 'number':
19499 			num = ch;
19500 			break;
19501 		case 'string':
19502 			num = IString.toCodePoint(ch, 0);
19503 			break;
19504 		case 'undefined':
19505 			return false;
19506 		default:
19507 			num = ch._toCodePoint(0);
19508 			break;
19509 	}
19510 
19511 	return CType._inRange(num, 'xdigit', ilib.data.ctype);
19512 };
19513 
19514 /**
19515  * @protected
19516  * @param {boolean} sync
19517  * @param {Object|undefined} loadParams
19518  * @param {function(*)|undefined} onLoad
19519  */
19520 isXdigit._init = function (sync, loadParams, onLoad) {
19521 	CType._init(sync, loadParams, onLoad);
19522 };
19523 
19524 
19525 /*< isScript.js */
19526 /*
19527  * isScript.js - Character type is script
19528  * 
19529  * Copyright © 2012-2015, JEDLSoft
19530  *
19531  * Licensed under the Apache License, Version 2.0 (the "License");
19532  * you may not use this file except in compliance with the License.
19533  * You may obtain a copy of the License at
19534  *
19535  *     http://www.apache.org/licenses/LICENSE-2.0
19536  *
19537  * Unless required by applicable law or agreed to in writing, software
19538  * distributed under the License is distributed on an "AS IS" BASIS,
19539  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19540  *
19541  * See the License for the specific language governing permissions and
19542  * limitations under the License.
19543  */
19544 
19545 // !depends CType.js IString.js
19546 
19547 // !data scriptToRange
19548 
19549 
19550 
19551 /**
19552  * Return whether or not the first character in the given string is 
19553  * in the given script. The script is given as the 4-letter ISO
19554  * 15924 script code.<p>
19555  * 
19556  * @static
19557  * @param {string|IString|number} ch character or code point to examine
19558  * @param {string} script the 4-letter ISO 15924 to query against
19559  * @return {boolean} true if the first character is in the given script, and
19560  * false otherwise
19561  */
19562 var isScript = function (ch, script) {
19563 	var num;
19564 	switch (typeof(ch)) {
19565 		case 'number':
19566 			num = ch;
19567 			break;
19568 		case 'string':
19569 			num = IString.toCodePoint(ch, 0);
19570 			break;
19571 		case 'undefined':
19572 			return false;
19573 		default:
19574 			num = ch._toCodePoint(0);
19575 			break;
19576 	}
19577 
19578 	return CType._inRange(num, script, ilib.data.scriptToRange);
19579 };
19580 
19581 /**
19582  * @protected
19583  * @param {boolean} sync
19584  * @param {Object|undefined} loadParams
19585  * @param {function(*)|undefined} onLoad
19586  */
19587 isScript._init = function (sync, loadParams, onLoad) {
19588 	CType._load("scriptToRange", sync, loadParams, onLoad);
19589 };
19590 
19591 
19592 /*< ScriptInfo.js */
19593 /*
19594  * ScriptInfo.js - information about scripts
19595  * 
19596  * Copyright © 2012-2015, JEDLSoft
19597  *
19598  * Licensed under the Apache License, Version 2.0 (the "License");
19599  * you may not use this file except in compliance with the License.
19600  * You may obtain a copy of the License at
19601  *
19602  *     http://www.apache.org/licenses/LICENSE-2.0
19603  *
19604  * Unless required by applicable law or agreed to in writing, software
19605  * distributed under the License is distributed on an "AS IS" BASIS,
19606  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19607  *
19608  * See the License for the specific language governing permissions and
19609  * limitations under the License.
19610  */
19611 
19612 // !depends ilib.js Utils.js
19613 
19614 // !data scripts
19615 
19616 
19617 /**
19618  * @class
19619  * Create a new script info instance. This class encodes information about
19620  * scripts, which are sets of characters used in a writing system.<p>
19621  * 
19622  * The options object may contain any of the following properties:
19623  * 
19624  * <ul>
19625  * <li><i>onLoad</i> - a callback function to call when the script info object is fully 
19626  * loaded. When the onLoad option is given, the script info object will attempt to
19627  * load any missing locale data using the ilib loader callback.
19628  * When the constructor is done (even if the data is already preassembled), the 
19629  * onLoad function is called with the current instance as a parameter, so this
19630  * callback can be used with preassembled or dynamic loading or a mix of the two.
19631  * 
19632  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
19633  * asynchronously. If this option is given as "false", then the "onLoad"
19634  * callback must be given, as the instance returned from this constructor will
19635  * not be usable for a while. 
19636  *
19637  * <li><i>loadParams</i> - an object containing parameters to pass to the 
19638  * loader callback function when locale data is missing. The parameters are not
19639  * interpretted or modified in any way. They are simply passed along. The object 
19640  * may contain any property/value pairs as long as the calling code is in
19641  * agreement with the loader callback function as to what those parameters mean.
19642  * </ul>
19643  * 
19644  * 
19645  * @constructor
19646  * @param {string} script The ISO 15924 4-letter identifier for the script
19647  * @param {Object} options parameters to initialize this matcher 
19648  */
19649 var ScriptInfo = function(script, options) {
19650 	var sync = true,
19651 	    loadParams = undefined;
19652 	
19653 	this.script = script;
19654 	
19655 	if (options) {
19656 		if (typeof(options.sync) !== 'undefined') {
19657 			sync = (options.sync == true);
19658 		}
19659 		
19660 		if (typeof(options.loadParams) !== 'undefined') {
19661 			loadParams = options.loadParams;
19662 		}
19663 	}
19664 
19665 	if (!ScriptInfo.cache) {
19666 		ScriptInfo.cache = {};
19667 	}
19668 
19669 	if (!ilib.data.scripts) {
19670 		Utils.loadData({
19671 			object: ScriptInfo, 
19672 			locale: "-", 
19673 			name: "scripts.json", 
19674 			sync: sync, 
19675 			loadParams: loadParams, 
19676 			callback: ilib.bind(this, function (info) {
19677 				if (!info) {
19678 					info = {"Latn":{"nb":215,"nm":"Latin","lid":"Latin","rtl":false,"ime":false,"casing":true}};
19679 					var spec = this.locale.getSpec().replace(/-/g, "_");
19680 					ScriptInfo.cache[spec] = info;
19681 				}
19682 				ilib.data.scripts = info;
19683 				this.info = script && ilib.data.scripts[script];
19684 				if (options && typeof(options.onLoad) === 'function') {
19685 					options.onLoad(this);
19686 				}
19687 			})
19688 		});
19689 	} else {
19690 		this.info = ilib.data.scripts[script];
19691 	}
19692 
19693 };
19694 
19695 /**
19696  * @private
19697  */
19698 ScriptInfo._getScriptsArray = function() {
19699 	var ret = [],
19700 		script = undefined,
19701 		scripts = ilib.data.scripts;
19702 
19703 	for (script in scripts) {
19704 		if (script && scripts[script]) {
19705 			ret.push(script);
19706 		}
19707 	}
19708 	
19709 	return ret;
19710 };
19711 
19712 /**
19713  * Return an array of all ISO 15924 4-letter identifier script identifiers that
19714  * this copy of ilib knows about.
19715  * @static
19716  * @param {boolean} sync whether to find the available ids synchronously (true) or asynchronously (false)
19717  * @param {Object} loadParams arbitrary object full of properties to pass to the loader
19718  * @param {function(Array.<string>)} onLoad callback function to call when the data is finished loading
19719  * @return {Array.<string>} an array of all script identifiers that this copy of
19720  * ilib knows about
19721  */
19722 ScriptInfo.getAllScripts = function(sync, loadParams, onLoad) {
19723 	if (!ilib.data.scripts) {
19724 		Utils.loadData({
19725 			object: ScriptInfo, 
19726 			locale: "-", 
19727 			name: "scripts.json", 
19728 			sync: sync, 
19729 			loadParams: loadParams, 
19730 			callback: ilib.bind(this, function (info) {
19731 				ilib.data.scripts = info;
19732 				
19733 				if (typeof(onLoad) === 'function') {
19734 					onLoad(ScriptInfo._getScriptsArray());
19735 				}
19736 			})
19737 		});
19738 	}
19739 	
19740 	return ScriptInfo._getScriptsArray();
19741 };
19742 
19743 ScriptInfo.prototype = {
19744 	/**
19745 	 * Return the 4-letter ISO 15924 identifier associated
19746 	 * with this script.
19747 	 * @return {string} the 4-letter ISO code for this script
19748 	 */
19749 	getCode: function () {
19750 		return this.info && this.script;
19751 	},
19752 	
19753 	/**
19754 	 * Get the ISO 15924 code number associated with this
19755 	 * script.
19756 	 * 
19757 	 * @return {number} the ISO 15924 code number
19758 	 */
19759 	getCodeNumber: function () {
19760 		return this.info && this.info.nb || 0;
19761 	},
19762 	
19763 	/**
19764 	 * Get the name of this script in English.
19765 	 * 
19766 	 * @return {string} the name of this script in English
19767 	 */
19768 	getName: function () {
19769 		return this.info && this.info.nm;
19770 	},
19771 	
19772 	/**
19773 	 * Get the long identifier assciated with this script.
19774 	 * 
19775 	 * @return {string} the long identifier of this script
19776 	 */
19777 	getLongCode: function () {
19778 		return this.info && this.info.lid;
19779 	},
19780 	
19781 	/**
19782 	 * Return the usual direction that text in this script is written
19783 	 * in. Possible return values are "rtl" for right-to-left,
19784 	 * "ltr" for left-to-right, and "ttb" for top-to-bottom.
19785 	 * 
19786 	 * @return {string} the usual direction that text in this script is
19787 	 * written in
19788 	 */
19789 	getScriptDirection: function() {
19790 		return (this.info && typeof(this.info.rtl) !== 'undefined' && this.info.rtl) ? "rtl" : "ltr";
19791 	},
19792 	
19793 	/**
19794 	 * Return true if this script typically requires an input method engine
19795 	 * to enter its characters.
19796 	 * 
19797 	 * @return {boolean} true if this script typically requires an IME
19798 	 */
19799 	getNeedsIME: function () {
19800 		return this.info && this.info.ime ? true : false; // converts undefined to false
19801 	},
19802 	
19803 	/**
19804 	 * Return true if this script uses lower- and upper-case characters.
19805 	 * 
19806 	 * @return {boolean} true if this script uses letter case
19807 	 */
19808 	getCasing: function () {
19809 		return this.info && this.info.casing ? true : false; // converts undefined to false
19810 	}
19811 };
19812 
19813 
19814 /*< Name.js */
19815 /*
19816  * Name.js - Person name parser
19817  *
19818  * Copyright © 2013-2015, JEDLSoft
19819  *
19820  * Licensed under the Apache License, Version 2.0 (the "License");
19821  * you may not use this file except in compliance with the License.
19822  * You may obtain a copy of the License at
19823  *
19824  *     http://www.apache.org/licenses/LICENSE-2.0
19825  *
19826  * Unless required by applicable law or agreed to in writing, software
19827  * distributed under the License is distributed on an "AS IS" BASIS,
19828  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19829  *
19830  * See the License for the specific language governing permissions and
19831  * limitations under the License.
19832  */
19833 
19834 /* !depends 
19835 ilib.js 
19836 Locale.js
19837 Utils.js 
19838 isAlpha.js 
19839 isIdeo.js 
19840 isPunct.js 
19841 isSpace.js
19842 JSUtils.js 
19843 IString.js
19844 */
19845 
19846 // !data name
19847 
19848 // notes:
19849 // icelandic given names: http://en.wiktionary.org/wiki/Appendix:Icelandic_given_names
19850 // danish approved given names: http://www.familiestyrelsen.dk/samliv/navne/
19851 // http://www.mentalfloss.com/blogs/archives/59277
19852 // other countries with first name restrictions: Norway, China, New Zealand, Japan, Sweden, Germany, Hungary
19853 
19854 
19855 
19856 /**
19857  * @class
19858  * A class to parse names of people. Different locales have different conventions when it
19859  * comes to naming people.<p>
19860  *
19861  * The options can contain any of the following properties:
19862  *
19863  * <ul>
19864  * <li><i>locale</i> - use the rules and conventions of the given locale in order to parse
19865  * the name
19866  * <li><i>style</i> - explicitly use the named style to parse the name. Valid values so
19867  * far are "western" and "asian". If this property is not specified, then the style will
19868  * be gleaned from the name itself. This class will count the total number of Latin or Asian
19869  * characters. If the majority of the characters are in one style, that style will be
19870  * used to parse the whole name.
19871  * <li><i>order</i> - explicitly use the given order for names. In some locales, such
19872  * as Russian, names may be written equally validly as "givenName familyName" or "familyName
19873  * givenName". This option tells the parser which order to prefer, and overrides the
19874  * default order for the locale. Valid values are "gf" (given-family) or "fg" (family-given).
19875  * <li><i>useSpaces</i> - explicitly specifies whether to use spaces or not between the given name , middle name
19876  * and family name.
19877  * <li>onLoad - a callback function to call when the name info is fully
19878  * loaded and the name has been parsed. When the onLoad option is given, the name object
19879  * will attempt to load any missing locale data using the ilib loader callback.
19880  * When the constructor is done (even if the data is already preassembled), the
19881  * onLoad function is called with the current instance as a parameter, so this
19882  * callback can be used with preassembled or dynamic loading or a mix of the two.
19883  *
19884  * <li>sync - tell whether to load any missing locale data synchronously or
19885  * asynchronously. If this option is given as "false", then the "onLoad"
19886  * callback must be given, as the instance returned from this constructor will
19887  * not be usable for a while.
19888  *
19889  * <li><i>loadParams</i> - an object containing parameters to pass to the
19890  * loader callback function when locale data is missing. The parameters are not
19891  * interpretted or modified in any way. They are simply passed along. The object
19892  * may contain any property/value pairs as long as the calling code is in
19893  * agreement with the loader callback function as to what those parameters mean.
19894  * </ul>
19895  *
19896  * When the parser has completed its parsing, it fills in the fields listed below.<p>
19897  *
19898  * For names that include auxilliary words, such as the family name "van der Heijden", all
19899  * of the auxilliary words ("van der") will be included in the field.<p>
19900  *
19901  * For names in Spanish locales, it is assumed that the family name is doubled. That is,
19902  * a person may have a paternal family name followed by a maternal family name. All
19903  * family names will be listed in the familyName field as normal, separated by spaces.
19904  * When formatting the short version of such names, only the paternal family name will
19905  * be used.
19906  *
19907  *
19908  * @constructor
19909  * @param {string|Name=} name the name to parse
19910  * @param {Object=} options Options governing the construction of this name instance
19911  */
19912 var Name = function (name, options) {
19913     var sync = true;
19914 
19915     if (!name || name.length === 0) {
19916     	return;
19917     }
19918 
19919     this.loadParams = {};
19920 
19921     if (options) {
19922         if (options.locale) {
19923             this.locale = (typeof (options.locale) === 'string') ? new Locale(options.locale) : options.locale;
19924         }
19925 
19926         if (options.style && (options.style === "asian" || options.style === "western")) {
19927             this.style = options.style;
19928         }
19929 
19930         if (options.order && (options.order === "gmf" || options.order === "fmg" || options.order === "fgm")) {
19931             this.order = options.order;
19932         }
19933 
19934         if (typeof (options.sync) !== 'undefined') {
19935             sync = (options.sync == true);
19936         }
19937 
19938         if (typeof (options.loadParams) !== 'undefined') {
19939             this.loadParams = options.loadParams;
19940         }
19941     }
19942 
19943     if (!Name.cache) {
19944         Name.cache = {};
19945     }
19946 
19947 	this.locale = this.locale || new Locale();
19948 	
19949 	isAlpha._init(sync, this.loadParams, ilib.bind(this, function() {
19950 		isIdeo._init(sync, this.loadParams, ilib.bind(this, function() {
19951 			isPunct._init(sync, this.loadParams, ilib.bind(this, function() {
19952 				isSpace._init(sync, this.loadParams, ilib.bind(this, function() {
19953 					Utils.loadData({
19954 						object: Name, 
19955 						locale: this.locale, 
19956 						name: "name.json", 
19957 						sync: sync, 
19958 						loadParams: this.loadParams, 
19959 						callback: ilib.bind(this, function (info) {
19960 							if (!info) {
19961 								info = Name.defaultInfo;
19962 								var spec = this.locale.getSpec().replace(/-/g, "_");
19963 								Name.cache[spec] = info;
19964 							}
19965                             if (typeof (name) === 'object') {
19966     							// copy constructor
19967 							    /**
19968 							     * The prefixes for this name
19969 							     * @type {string|Array.<string>}
19970 							     */
19971 							    this.prefix = name.prefix;
19972 							    /**
19973 							     * The given (personal) name in this name.
19974 							     * @type {string|Array.<string>}
19975 							     */
19976 							    this.givenName = name.givenName;
19977 							    /**
19978 							     * The middle names used in this name. If there are multiple middle names, they all
19979 							     * appear in this field separated by spaces.
19980 							     * @type {string|Array.<string>}
19981 							     */
19982 							    this.middleName = name.middleName;
19983 							    /**
19984 							     * The family names in this name. If there are multiple family names, they all
19985 							     * appear in this field separated by spaces.
19986 							     * @type {string|Array.<string>}
19987 							     */
19988 							    this.familyName = name.familyName;
19989 							    /**
19990 							     * The suffixes for this name. If there are multiple suffixes, they all
19991 							     * appear in this field separated by spaces.
19992 							     * @type {string|Array.<string>}
19993 							     */
19994 							    this.suffix = name.suffix;
19995 
19996 							    // private properties
19997 							    this.locale = name.locale;
19998 							    this.style = name.style;
19999 							    this.order = name.order;
20000 							    this.useSpaces = name.useSpaces;
20001 							    this.isAsianName = name.isAsianName;
20002 					    	    return;
20003 						    }
20004 							/** 
20005 							 * @type {{
20006 							 *   nameStyle:string,
20007 							 *   order:string,
20008 							 *   prefixes:Array.<string>,
20009 							 *   suffixes:Array.<string>,
20010 							 *   auxillaries:Array.<string>,
20011 							 *   honorifics:Array.<string>,
20012 							 *   knownFamilyNames:Array.<string>,
20013 							 *   noCompoundFamilyNames:boolean,
20014 							 *   sortByHeadWord:boolean
20015 							 * }} */
20016 							this.info = info;
20017 							this._init(name);
20018 							if (options && typeof(options.onLoad) === 'function') {
20019 								options.onLoad(this);
20020 							}
20021 						})
20022 					});					
20023 				}));
20024 			}));
20025 		}));
20026 	}));
20027 };
20028 
20029 Name.defaultInfo = ilib.data.name ||  {
20030 	"components": {
20031 		"short": {
20032 			"g": 1,
20033 			"f": 1
20034 		},
20035 		"medium": {
20036 			"g": 1,
20037 			"m": 1,
20038 			"f": 1
20039 		},
20040 		"long": {
20041 			"p": 1,
20042 			"g": 1,
20043 			"m": 1,
20044 			"f": 1
20045 		},
20046 		"full": {
20047 			"p": 1,
20048 			"g": 1,
20049 			"m": 1,
20050 			"f": 1,
20051 			"s": 1
20052 		}
20053 	},
20054 	"format": "{prefix} {givenName} {middleName} {familyName}{suffix}",
20055 	"sortByHeadWord": false,
20056 	"nameStyle": "western",
20057 	"conjunctions": {
20058 		"and1": "and",
20059 		"and2": "and",
20060 		"or1": "or",
20061 		"or2": "or"
20062 	},
20063 	"auxillaries": {
20064 		"von": 1,
20065 		"von der": 1,
20066 		"von den": 1,
20067 		"van": 1,
20068 		"van der": 1,
20069 		"van de": 1,
20070 		"van den": 1,
20071 		"de": 1,
20072 		"di": 1,
20073 		"la": 1,
20074 		"lo": 1,
20075 		"des": 1,
20076 		"le": 1,
20077 		"les": 1,
20078 		"du": 1,
20079 		"de la": 1,
20080 		"del": 1,
20081 		"de los": 1,
20082 		"de las": 1
20083 	},
20084 	"prefixes": [
20085         "doctor",
20086         "dr",
20087         "mr",
20088         "mrs",
20089         "ms",
20090         "mister",
20091         "madame",
20092         "madamoiselle",
20093         "miss",
20094         "monsieur",
20095         "señor",
20096         "señora",
20097         "señorita"
20098 	],
20099 	"suffixes": [
20100         ",",
20101         "junior",
20102         "jr",
20103         "senior",
20104         "sr",
20105         "i",
20106         "ii",
20107         "iii",
20108         "esq",
20109         "phd",
20110         "md"
20111 	],
20112     "patronymicName":[ ],
20113     "familyNames":[ ]
20114 };
20115 
20116 /**
20117  * Return true if the given character is in the range of the Han, Hangul, or kana
20118  * scripts.
20119  * @static
20120  * @protected
20121  */
20122 Name._isAsianChar = function(c) {
20123 	return isIdeo(c) ||
20124 		CType.withinRange(c, "hangul") ||
20125 		CType.withinRange(c, "hiragana") ||
20126 		CType.withinRange(c, "katakana");
20127 };
20128 
20129 
20130 /**
20131  * @static
20132  * @protected
20133  */
20134 Name._isAsianName = function (name, language) {
20135     // the idea is to count the number of asian chars and the number
20136     // of latin chars. If one is greater than the other, choose
20137     // that style.
20138     var asian = 0,
20139         latin = 0,
20140         i;
20141 
20142     if (name && name.length > 0) {
20143         for (i = 0; i < name.length; i++) {
20144         	var c = name.charAt(i);
20145 
20146             if (Name._isAsianChar(c)) {
20147                 if (language =="ko" || language =="ja" || language =="zh") {
20148                     return true;
20149                 }
20150                 asian++;
20151             } else if (isAlpha(c)) {
20152                 if (!language =="ko" || !language =="ja" || !language =="zh") {
20153                     return false;
20154                 }
20155                 latin++;
20156             }
20157         }
20158 
20159         return latin < asian;
20160     }
20161 
20162     return false;
20163 };
20164 
20165 /**
20166  * Return true if any Latin letters are found in the string. Return
20167  * false if all the characters are non-Latin.
20168  * @static
20169  * @protected
20170  */
20171 Name._isEuroName = function (name, language) {
20172     var c,
20173         n = new IString(name),
20174         it = n.charIterator();
20175 
20176     while (it.hasNext()) {
20177         c = it.next();
20178 
20179         if (!Name._isAsianChar(c) && !isPunct(c) && !isSpace(c)) {
20180             return true;
20181         } else if (Name._isAsianChar(c) && (language =="ko" || language =="ja" || language =="zh")) {
20182             return false;
20183         }
20184     }
20185     return false;
20186 };
20187 
20188 Name.prototype = {
20189     /**
20190      * @protected
20191      */
20192     _init: function (name) {
20193         var parts, prefixArray, prefix, prefixLower,
20194             suffixArray, suffix, suffixLower,
20195             i, info, hpSuffix;
20196         var currentLanguage = this.locale.getLanguage();
20197 
20198         if (name) {
20199             // for DFISH-12905, pick off the part that the LDAP server automatically adds to our names in HP emails
20200             i = name.search(/\s*[,\/\(\[\{<]/);
20201             if (i !== -1) {
20202                 hpSuffix = name.substring(i);
20203                 hpSuffix = hpSuffix.replace(/\s+/g, ' '); // compress multiple whitespaces
20204                 suffixArray = hpSuffix.split(" ");
20205                 var conjunctionIndex = this._findLastConjunction(suffixArray);
20206                 if (conjunctionIndex > -1) {
20207                     // it's got conjunctions in it, so this is not really a suffix
20208                     hpSuffix = undefined;
20209                 } else {
20210                     name = name.substring(0, i);
20211                 }
20212             }
20213 
20214             this.isAsianName = Name._isAsianName(name, currentLanguage);
20215             if (this.info.nameStyle === "asian" || this.info.order === "fmg" || this.info.order === "fgm") {
20216                 info = this.isAsianName ? this.info : ilib.data.name;
20217             } else {
20218                 info = this.isAsianName ? ilib.data.name : this.info;
20219             }
20220 
20221             if (this.isAsianName) {
20222                 // all-asian names
20223                 if (this.useSpaces == false) {
20224                     name = name.replace(/\s+/g, ''); // eliminate all whitespaces
20225                 }
20226                 parts = name.trim().split('');
20227             }
20228             //} 
20229             else {
20230                 name = name.replace(/, /g, ' , ');
20231                 name = name.replace(/\s+/g, ' '); // compress multiple whitespaces
20232                 parts = name.trim().split(' ');
20233             }
20234 
20235             // check for prefixes
20236             if (parts.length > 1) {
20237                 for (i = parts.length; i > 0; i--) {
20238                     prefixArray = parts.slice(0, i);
20239                     prefix = prefixArray.join(this.isAsianName ? '' : ' ');
20240                     prefixLower = prefix.toLowerCase();
20241                     prefixLower = prefixLower.replace(/[,\.]/g, ''); // ignore commas and periods
20242                     if (ilib.isArray(this.info.prefixes) &&
20243                         (JSUtils.indexOf(this.info.prefixes, prefixLower) > -1 || this._isConjunction(prefixLower))) {
20244                         if (this.prefix) {
20245                             if (!this.isAsianName) {
20246                                 this.prefix += ' ';
20247                             }
20248                             this.prefix += prefix;
20249                         } else {
20250                             this.prefix = prefix;
20251                         }
20252                         parts = parts.slice(i);
20253                         i = parts.length;
20254                     }
20255                 }
20256             }
20257             // check for suffixes
20258             if (parts.length > 1) {
20259                 for (i = parts.length; i > 0; i--) {
20260                     suffixArray = parts.slice(-i);
20261                     suffix = suffixArray.join(this.isAsianName ? '' : ' ');
20262                     suffixLower = suffix.toLowerCase();
20263                     suffixLower = suffixLower.replace(/[\.]/g, ''); // ignore periods
20264                     if (ilib.isArray(this.info.suffixes) && JSUtils.indexOf(this.info.suffixes, suffixLower) > -1) {
20265                         if (this.suffix) {
20266                             if (!this.isAsianName && !isPunct(this.suffix.charAt(0))) {
20267                                 this.suffix = ' ' + this.suffix;
20268                             }
20269                             this.suffix = suffix + this.suffix;
20270                         } else {
20271                             this.suffix = suffix;
20272                         }
20273                         parts = parts.slice(0, parts.length - i);
20274                         i = parts.length;
20275                     }
20276                 }
20277             }
20278 
20279             if (hpSuffix) {
20280                 this.suffix = (this.suffix && this.suffix + hpSuffix) || hpSuffix;
20281             }
20282 
20283             // adjoin auxillary words to their headwords
20284             if (parts.length > 1 && !this.isAsianName) {
20285                 parts = this._joinAuxillaries(parts, this.isAsianName);
20286             }
20287 
20288             if (this.isAsianName) {
20289                 this._parseAsianName(parts, currentLanguage);
20290             } else {
20291                 this._parseWesternName(parts);
20292             }
20293 
20294             this._joinNameArrays();
20295         }
20296     },
20297 
20298     /**
20299 	 * @return {number} 
20300 	 *
20301 	_findSequence: function(parts, hash, isAsian) {
20302 		var sequence, sequenceLower, sequenceArray, aux = [], i, ret = {};
20303 		
20304 		if (parts.length > 0 && hash) {
20305 			//console.info("_findSequence: finding sequences");
20306 			for (var start = 0; start < parts.length-1; start++) {
20307 				for ( i = parts.length; i > start; i-- ) {
20308 					sequenceArray = parts.slice(start, i);
20309 					sequence = sequenceArray.join(isAsian ? '' : ' ');
20310 					sequenceLower = sequence.toLowerCase();
20311 					sequenceLower = sequenceLower.replace(/[,\.]/g, '');  // ignore commas and periods
20312 					
20313 					//console.info("_findSequence: checking sequence: '" + sequenceLower + "'");
20314 					
20315 					if ( sequenceLower in hash ) {
20316 						ret.match = sequenceArray;
20317 						ret.start = start;
20318 						ret.end = i;
20319 						return ret;
20320 						//console.info("_findSequence: Found sequence '" + sequence + "' New parts list is " + JSON.stringify(parts));
20321 					}
20322 				}
20323 			}
20324 		}
20325 	
20326 		return undefined;
20327 	},
20328 	*/
20329 
20330     /**
20331      * @protected
20332      * @param {Array} parts
20333      * @param {Array} names
20334      * @param {boolean} isAsian
20335      * @param {boolean=} noCompoundPrefix
20336      */
20337     _findPrefix: function (parts, names, isAsian, noCompoundPrefix) {
20338         var i, prefix, prefixLower, prefixArray, aux = [];
20339 
20340         if (parts.length > 0 && names) {
20341             for (i = parts.length; i > 0; i--) {
20342                 prefixArray = parts.slice(0, i);
20343                 prefix = prefixArray.join(isAsian ? '' : ' ');
20344                 prefixLower = prefix.toLowerCase();
20345                 prefixLower = prefixLower.replace(/[,\.]/g, ''); // ignore commas and periods
20346 
20347                 if (prefixLower in names) {
20348                     aux = aux.concat(isAsian ? prefix : prefixArray);
20349                     if (noCompoundPrefix) {
20350                     	// don't need to parse further. Just return it as is.
20351                     	return aux;
20352                     }
20353                     parts = parts.slice(i);
20354                     i = parts.length + 1;
20355                 }
20356             }
20357         }
20358 
20359         return aux;
20360     },
20361 
20362     /**
20363      * @protected
20364      */
20365     _findSuffix: function (parts, names, isAsian) {
20366         var i, j, seq = "";
20367 
20368         for (i = 0; i < names.length; i++) {
20369             if (parts.length >= names[i].length) {
20370                 j = 0;
20371                 while (j < names[i].length && parts[parts.length - j] === names[i][names[i].length - j]) {
20372                     j++;
20373                 }
20374                 if (j >= names[i].length) {
20375                     seq = parts.slice(parts.length - j).join(isAsian ? "" : " ") + (isAsian ? "" : " ") + seq;
20376                     parts = parts.slice(0, parts.length - j);
20377                     i = -1; // restart the search
20378                 }
20379             }
20380         }
20381 
20382         this.suffix = seq;
20383         return parts;
20384     },
20385 
20386     /**
20387      * @protected
20388      * Tell whether or not the given word is a conjunction in this language.
20389      * @param {string} word the word to test
20390      * @return {boolean} true if the word is a conjunction
20391      */
20392     _isConjunction: function _isConjunction(word) {
20393         return (this.info.conjunctions.and1 === word ||
20394             this.info.conjunctions.and2 === word ||
20395             this.info.conjunctions.or1 === word ||
20396             this.info.conjunctions.or2 === word ||
20397             ("&" === word) ||
20398             ("+" === word));
20399     },
20400 
20401     /**
20402      * Find the last instance of 'and' in the name
20403      * @protected
20404      * @param {Array.<string>} parts
20405      * @return {number}
20406      */
20407     _findLastConjunction: function _findLastConjunction(parts) {
20408         var conjunctionIndex = -1,
20409             index, part;
20410 
20411         for (index = 0; index < parts.length; index++) {
20412             part = parts[index];
20413             if (typeof (part) === 'string') {
20414                 part = part.toLowerCase();
20415                 // also recognize English
20416                 if ("and" === part || "or" === part || "&" === part || "+" === part) {
20417                     conjunctionIndex = index;
20418                 }
20419                 if (this._isConjunction(part)) {
20420                     conjunctionIndex = index;
20421                 }
20422             }
20423         }
20424         return conjunctionIndex;
20425     },
20426 
20427     /**
20428      * @protected
20429      * @param {Array.<string>} parts the current array of name parts
20430      * @param {boolean} isAsian true if the name is being parsed as an Asian name
20431      * @return {Array.<string>} the remaining parts after the prefixes have been removed
20432      */
20433     _extractPrefixes: function (parts, isAsian) {
20434         var i = this._findPrefix(parts, this.info.prefixes, isAsian);
20435         if (i > 0) {
20436             this.prefix = parts.slice(0, i).join(isAsian ? "" : " ");
20437             return parts.slice(i);
20438         }
20439         // prefixes not found, so just return the array unmodified
20440         return parts;
20441     },
20442 
20443     /**
20444      * @protected
20445      * @param {Array.<string>} parts the current array of name parts
20446      * @param {boolean} isAsian true if the name is being parsed as an Asian name
20447      * @return {Array.<string>} the remaining parts after the suffices have been removed
20448      */
20449     _extractSuffixes: function (parts, isAsian) {
20450         var i = this._findSuffix(parts, this.info.suffixes, isAsian);
20451         if (i > 0) {
20452             this.suffix = parts.slice(i).join(isAsian ? "" : " ");
20453             return parts.slice(0, i);
20454         }
20455         // suffices not found, so just return the array unmodified
20456         return parts;
20457     },
20458 
20459     /**
20460      * Adjoin auxillary words to their head words.
20461      * @protected
20462      * @param {Array.<string>} parts the current array of name parts
20463      * @param {boolean} isAsian true if the name is being parsed as an Asian name
20464      * @return {Array.<string>} the parts after the auxillary words have been plucked onto their head word
20465      */
20466     _joinAuxillaries: function (parts, isAsian) {
20467         var start, i, prefixArray, prefix, prefixLower;
20468 
20469         if (this.info.auxillaries && (parts.length > 2 || this.prefix)) {
20470             for (start = 0; start < parts.length - 1; start++) {
20471                 for (i = parts.length; i > start; i--) {
20472                     prefixArray = parts.slice(start, i);
20473                     prefix = prefixArray.join(' ');
20474                     prefixLower = prefix.toLowerCase();
20475                     prefixLower = prefixLower.replace(/[,\.]/g, ''); // ignore commas and periods
20476 
20477                     if (prefixLower in this.info.auxillaries) {
20478                         parts.splice(start, i + 1 - start, prefixArray.concat(parts[i]));
20479                         i = start;
20480                     }
20481                 }
20482             }
20483         }
20484 
20485         return parts;
20486     },
20487 
20488     /**
20489      * Recursively join an array or string into a long string.
20490      * @protected
20491      */
20492     _joinArrayOrString: function _joinArrayOrString(part) {
20493         var i;
20494         if (typeof (part) === 'object') {
20495             for (i = 0; i < part.length; i++) {
20496                 part[i] = this._joinArrayOrString(part[i]);
20497             }
20498             var ret = "";
20499             part.forEach(function (segment) {
20500                 if (ret.length > 0 && !isPunct(segment.charAt(0))) {
20501                     ret += ' ';
20502                 }
20503                 ret += segment;
20504             });
20505 
20506             return ret;
20507         }
20508 
20509         return part;
20510     },
20511 
20512     /**
20513      * @protected
20514      */
20515     _joinNameArrays: function _joinNameArrays() {
20516         var prop;
20517         for (prop in this) {
20518 
20519             if (this[prop] !== undefined && typeof (this[prop]) === 'object' && ilib.isArray(this[prop])) {
20520 
20521                 this[prop] = this._joinArrayOrString(this[prop]);
20522             }
20523         }
20524     },
20525 
20526     /**
20527      * @protected
20528      */
20529     _parseAsianName: function (parts, language) {
20530         var familyNameArray = this._findPrefix(parts, this.info.knownFamilyNames, true, this.info.noCompoundFamilyNames);
20531         var tempFullName = parts.join('');
20532 
20533         if (familyNameArray && familyNameArray.length > 0) {
20534             this.familyName = familyNameArray.join('');
20535             this.givenName = parts.slice(this.familyName.length).join('');
20536             
20537             //Overide parsing rules if spaces are found in korean
20538             if (language === "ko" && tempFullName.search(/\s*[/\s]/) > -1 && !this.suffix) {
20539                 this._parseKoreanName(tempFullName);
20540             }
20541         } else if (this.locale.getLanguage() === "ja") {
20542             this._parseJapaneseName(parts);
20543         } else if (this.suffix || this.prefix) {
20544             this.familyName = parts.join('');
20545         } else {
20546             this.givenName = parts.join('');
20547         }
20548     },
20549 
20550     /**
20551      * @protected
20552      */
20553     _parseKoreanName: function (name) {
20554         var tempName = name;
20555 
20556         var spaceSplit = tempName.split(" ");
20557         var spceCount = spaceSplit.length;
20558         var fistSpaceIndex = tempName.indexOf(" ");
20559         var lastSpaceIndex = tempName.lastIndexOf(" ");
20560 
20561         if (spceCount === 2) {
20562             this.familyName = spaceSplit[0];
20563             this.givenName = tempName.slice(fistSpaceIndex, tempName.length);
20564         } else {
20565             this.familyName = spaceSplit[0];
20566             this.middleName = tempName.slice(fistSpaceIndex, lastSpaceIndex);
20567             this.givenName = tempName.slice(lastSpaceIndex, tempName.length);
20568         }
20569         
20570     },
20571 
20572     /**
20573      * @protected
20574      */
20575     _parseJapaneseName: function (parts) {
20576     	if (this.suffix && this.suffix.length > 1 && this.info.honorifics.indexOf(this.suffix)>-1) {
20577     		if (parts.length === 1) {
20578     			if (CType.withinRange(parts[0], "cjk")) {
20579     				this.familyName = parts[0];
20580     			} else {
20581     				this.givenName = parts[0];
20582     			}
20583     			return;
20584     		} else if (parts.length === 2) {
20585     			this.familyName = parts.slice(0,parts.length).join("")
20586     			return;
20587     		}
20588     	}
20589     	if (parts.length > 1) {
20590     		var fn = "";                                                                    
20591     		for (var i = 0; i < parts.length; i++) {
20592     			if (CType.withinRange(parts[i], "cjk")) {
20593     				fn += parts[i];
20594     			} else if (fn.length > 1 && CType.withinRange(parts[i], "hiragana")) {
20595     				this.familyName = fn;
20596     				this.givenName = parts.slice(i,parts.length).join("");
20597     				return;
20598     			} else {
20599     				break;
20600     			}
20601     		}
20602     	}
20603     	if (parts.length === 1) {
20604     		this.familyName = parts[0];
20605     	} else if (parts.length === 2) {
20606     		this.familyName = parts[0];
20607     		this.givenName = parts[1];
20608     	} else if (parts.length === 3) {
20609     		this.familyName = parts[0];
20610     		this.givenName = parts.slice(1,parts.length).join("");
20611     	} else if (parts.length > 3) {
20612     		this.familyName = parts.slice(0,2).join("")
20613     		this.givenName = parts.slice(2,parts.length).join("");
20614     	}      
20615     },
20616 
20617     /**
20618      * @protected
20619      */
20620     _parseSpanishName: function (parts) {
20621         var conjunctionIndex;
20622 
20623         if (parts.length === 1) {
20624             if (this.prefix || typeof (parts[0]) === 'object') {
20625                 this.familyName = parts[0];
20626             } else {
20627                 this.givenName = parts[0];
20628             }
20629         } else if (parts.length === 2) {
20630             // we do G F
20631             this.givenName = parts[0];
20632             this.familyName = parts[1];
20633         } else if (parts.length === 3) {
20634             conjunctionIndex = this._findLastConjunction(parts);
20635             // if there's an 'and' in the middle spot, put everything in the first name
20636             if (conjunctionIndex === 1) {
20637                 this.givenName = parts;
20638             } else {
20639                 // else, do G F F
20640                 this.givenName = parts[0];
20641                 this.familyName = parts.slice(1);
20642             }
20643         } else if (parts.length > 3) {
20644             //there are at least 4 parts to this name
20645 
20646             conjunctionIndex = this._findLastConjunction(parts);
20647             ////console.log("@@@@@@@@@@@@@@@@"+conjunctionIndex)
20648             if (conjunctionIndex > 0) {
20649                 // if there's a conjunction that's not the first token, put everything up to and 
20650                 // including the token after it into the first name, the last 2 tokens into
20651                 // the family name (if they exist) and everything else in to the middle name
20652                 // 0 1 2 3 4 5
20653                 // G A G
20654                 // G A G F
20655                 // G G A G
20656                 // G A G F F
20657                 // G G A G F
20658                 // G G G A G
20659                 // G A G M F F
20660                 // G G A G F F
20661                 // G G G A G F
20662                 // G G G G A G
20663                 this.givenName = parts.splice(0, conjunctionIndex + 2);
20664                 if (parts.length > 1) {
20665                     this.familyName = parts.splice(parts.length - 2, 2);
20666                     if (parts.length > 0) {
20667                         this.middleName = parts;
20668                     }
20669                 } else if (parts.length === 1) {
20670                     this.familyName = parts[0];
20671                 }
20672             } else {
20673                 this.givenName = parts.splice(0, 1);
20674                 this.familyName = parts.splice(parts.length - 2, 2);
20675                 this.middleName = parts;
20676             }
20677         }
20678     },
20679 
20680     /**
20681      * @protected
20682      */
20683     _parseIndonesianName: function (parts) {
20684         var conjunctionIndex;
20685 
20686         if (parts.length === 1) {
20687             //if (this.prefix || typeof(parts[0]) === 'object') {
20688             //this.familyName = parts[0];
20689             //} else {
20690             this.givenName = parts[0];
20691             //}
20692             //} else if (parts.length === 2) {
20693             // we do G F
20694             //this.givenName = parts[0];
20695             //this.familyName = parts[1];
20696         } else if (parts.length >= 2) {
20697             //there are at least 3 parts to this name
20698 
20699             conjunctionIndex = this._findLastConjunction(parts);
20700             if (conjunctionIndex > 0) {
20701                 // if there's a conjunction that's not the first token, put everything up to and 
20702                 // including the token after it into the first name, the last 2 tokens into
20703                 // the family name (if they exist) and everything else in to the middle name
20704                 // 0 1 2 3 4 5
20705                 // G A G
20706                 // G A G F
20707                 // G G A G
20708                 // G A G F F
20709                 // G G A G F
20710                 // G G G A G
20711                 // G A G M F F
20712                 // G G A G F F
20713                 // G G G A G F
20714                 // G G G G A G
20715                 this.givenName = parts.splice(0, conjunctionIndex + 2);
20716                 if (parts.length > 1) {
20717                     //this.familyName = parts.splice(parts.length-2, 2);
20718                     //if ( parts.length > 0 ) {
20719                     this.middleName = parts;
20720                 }
20721                 //} else if (parts.length === 1) {
20722                 //	this.familyName = parts[0];
20723                 //}
20724             } else {
20725                 this.givenName = parts.splice(0, 1);
20726                 //this.familyName = parts.splice(parts.length-2, 2);
20727                 this.middleName = parts;
20728             }
20729         }
20730     },
20731     
20732     /**
20733      * @protected
20734      */
20735     _parseGenericWesternName: function (parts) {
20736         /* Western names are parsed as follows, and rules are applied in this 
20737          * order:
20738          *
20739          * G
20740          * G F
20741          * G M F
20742          * G M M F
20743          * P F
20744          * P G F
20745          */
20746         var conjunctionIndex;
20747 
20748         if (parts.length === 1) {
20749             if (this.prefix || typeof (parts[0]) === 'object') {
20750                 // already has a prefix, so assume it goes with the family name like "Dr. Roberts" or
20751                 // it is a name with auxillaries, which is almost always a family name
20752                 this.familyName = parts[0];
20753             } else {
20754                 this.givenName = parts[0];
20755             }
20756         } else if (parts.length === 2) {
20757             // we do G F
20758             if (this.info.order == 'fgm') {
20759                 this.givenName = parts[1];
20760                 this.familyName = parts[0];
20761             } else if (this.info.order == "gmf" || typeof (this.info.order) == 'undefined') {
20762                 this.givenName = parts[0];
20763                 this.familyName = parts[1];
20764             }
20765         } else if (parts.length >= 3) {
20766             //find the first instance of 'and' in the name
20767             conjunctionIndex = this._findLastConjunction(parts);
20768 
20769             if (conjunctionIndex > 0) {
20770                 // if there's a conjunction that's not the first token, put everything up to and 
20771                 // including the token after it into the first name, the last token into
20772                 // the family name (if it exists) and everything else in to the middle name
20773                 // 0 1 2 3 4 5
20774                 // G A G M M F
20775                 // G G A G M F
20776                 // G G G A G F
20777                 // G G G G A G
20778                 //if(this.order == "gmf") {
20779                 this.givenName = parts.slice(0, conjunctionIndex + 2);
20780 
20781                 if (conjunctionIndex + 1 < parts.length - 1) {
20782                     this.familyName = parts.splice(parts.length - 1, 1);
20783                     ////console.log(this.familyName);
20784                     if (conjunctionIndex + 2 < parts.length - 1) {
20785                         this.middleName = parts.slice(conjunctionIndex + 2, parts.length - conjunctionIndex - 3);
20786                     }
20787                 } else if (this.order == "fgm") {
20788                     this.familyName = parts.slice(0, conjunctionIndex + 2);
20789                     if (conjunctionIndex + 1 < parts.length - 1) {
20790                         this.middleName = parts.splice(parts.length - 1, 1);
20791                         if (conjunctionIndex + 2 < parts.length - 1) {
20792                             this.givenName = parts.slice(conjunctionIndex + 2, parts.length - conjunctionIndex - 3);
20793                         }
20794                     }
20795                 }
20796             } else {
20797                 this.givenName = parts[0];
20798 
20799                 this.middleName = parts.slice(1, parts.length - 1);
20800 
20801                 this.familyName = parts[parts.length - 1];
20802             }
20803         }
20804     },
20805     
20806      /**
20807      * parse patrinomic name from the russian names 
20808      * @protected
20809      * @param {Array.<string>} parts the current array of name parts
20810      * @return number  index of the part which contains patronymic name
20811      */
20812     _findPatronymicName: function(parts) {
20813     	var index, part;
20814     	for (index = 0; index < parts.length; index++) {
20815     		part = parts[index];
20816     		if (typeof (part) === 'string') {
20817     			part = part.toLowerCase();
20818 
20819     			var subLength = this.info.patronymicName.length;
20820     			while(subLength--) {
20821     				if(part.indexOf(this.info.patronymicName[subLength])!== -1 )
20822     					return index;
20823     			}
20824     		}
20825     	}
20826     	return -1;
20827     },
20828 
20829     /**
20830 	 * find if the given part is patronymic name
20831 	 * 
20832 	 * @protected
20833 	 * @param {string} part string from name parts @
20834 	 * @return number index of the part which contains familyName
20835 	 */
20836     _isPatronymicName: function(part) {
20837 	    var pName;
20838 	    if ( typeof (part) === 'string') {
20839 		    pName = part.toLowerCase();
20840 
20841 		    var subLength = this.info.patronymicName.length;
20842 		    while (subLength--) {
20843 			    if (pName.indexOf(this.info.patronymicName[subLength]) !== -1)
20844 				    return true;
20845 		    }
20846 	    }
20847 	    return false;
20848     },
20849 
20850     /**
20851 	 * find family name from the russian name
20852 	 * 
20853 	 * @protected
20854 	 * @param {Array.<string>} parts the current array of name parts
20855 	 * @return boolean true if patronymic, false otherwise
20856 	 */
20857     _findFamilyName: function(parts) {
20858 	    var index, part, substring;
20859 	    for (index = 0; index < parts.length; index++) {
20860 		    part = parts[index];
20861 
20862 		    if ( typeof (part) === 'string') {
20863 			    part = part.toLowerCase();
20864 			    var length = part.length - 1;
20865 
20866 			    if (this.info.familyName.indexOf(part) !== -1) {
20867 				    return index;
20868 			    } else if (part[length] === 'в' || part[length] === 'н' ||
20869 			        part[length] === 'й') {
20870 				    substring = part.slice(0, -1);
20871 				    if (this.info.familyName.indexOf(substring) !== -1) {
20872 					    return index;
20873 				    }
20874 			    } else if ((part[length - 1] === 'в' && part[length] === 'а') ||
20875 			        (part[length - 1] === 'н' && part[length] === 'а') ||
20876 			        (part[length - 1] === 'а' && part[length] === 'я')) {
20877 				    substring = part.slice(0, -2);
20878 				    if (this.info.familyName.indexOf(substring) !== -1) {
20879 					    return index;
20880 				    }
20881 			    }
20882 		    }
20883 	    }
20884 	    return -1;
20885     },
20886 
20887     /**
20888 	 * parse russian name
20889 	 * 
20890 	 * @protected
20891 	 * @param {Array.<string>} parts the current array of name parts
20892 	 * @return
20893 	 */
20894     _parseRussianName: function(parts) {
20895 	    var conjunctionIndex, familyIndex = -1;
20896 
20897 	    if (parts.length === 1) {
20898 		    if (this.prefix || typeof (parts[0]) === 'object') {
20899 			    // already has a prefix, so assume it goes with the family name
20900 				// like "Dr. Roberts" or
20901 			    // it is a name with auxillaries, which is almost always a
20902 				// family name
20903 			    this.familyName = parts[0];
20904 		    } else {
20905 			    this.givenName = parts[0];
20906 		    }
20907 	    } else if (parts.length === 2) {
20908 		    // we do G F
20909 		    if (this.info.order === 'fgm') {
20910 			    this.givenName = parts[1];
20911 			    this.familyName = parts[0];
20912 		    } else if (this.info.order === "gmf") {
20913 			    this.givenName = parts[0];
20914 			    this.familyName = parts[1];
20915 		    } else if ( typeof (this.info.order) === 'undefined') {
20916 			    if (this._isPatronymicName(parts[1]) === true) {
20917 				    this.middleName = parts[1];
20918 				    this.givenName = parts[0];
20919 			    } else if ((familyIndex = this._findFamilyName(parts)) !== -1) {
20920 				    if (familyIndex === 1) {
20921 					    this.givenName = parts[0];
20922 					    this.familyName = parts[1];
20923 				    } else {
20924 					    this.familyName = parts[0];
20925 					    this.givenName = parts[1];
20926 				    }
20927 
20928 			    } else {
20929 				    this.givenName = parts[0];
20930 				    this.familyName = parts[1];
20931 			    }
20932 
20933 		    }
20934 	    } else if (parts.length >= 3) {
20935 		    // find the first instance of 'and' in the name
20936 		    conjunctionIndex = this._findLastConjunction(parts);
20937 		    var patronymicNameIndex = this._findPatronymicName(parts);
20938 		    if (conjunctionIndex > 0) {
20939 			    // if there's a conjunction that's not the first token, put
20940 				// everything up to and
20941 			    // including the token after it into the first name, the last
20942 				// token into
20943 			    // the family name (if it exists) and everything else in to the
20944 				// middle name
20945 			    // 0 1 2 3 4 5
20946 			    // G A G M M F
20947 			    // G G A G M F
20948 			    // G G G A G F
20949 			    // G G G G A G
20950 			    // if(this.order == "gmf") {
20951 			    this.givenName = parts.slice(0, conjunctionIndex + 2);
20952 
20953 			    if (conjunctionIndex + 1 < parts.length - 1) {
20954 				    this.familyName = parts.splice(parts.length - 1, 1);
20955 				    // //console.log(this.familyName);
20956 				    if (conjunctionIndex + 2 < parts.length - 1) {
20957 					    this.middleName = parts.slice(conjunctionIndex + 2,
20958 					        parts.length - conjunctionIndex - 3);
20959 				    }
20960 			    } else if (this.order == "fgm") {
20961 				    this.familyName = parts.slice(0, conjunctionIndex + 2);
20962 				    if (conjunctionIndex + 1 < parts.length - 1) {
20963 					    this.middleName = parts.splice(parts.length - 1, 1);
20964 					    if (conjunctionIndex + 2 < parts.length - 1) {
20965 						    this.givenName = parts.slice(conjunctionIndex + 2,
20966 						        parts.length - conjunctionIndex - 3);
20967 					    }
20968 				    }
20969 			    }
20970 		    } else if (patronymicNameIndex !== -1) {
20971 			    this.middleName = parts[patronymicNameIndex];
20972 
20973 			    if (patronymicNameIndex === (parts.length - 1)) {
20974 				    this.familyName = parts[0];
20975 				    this.givenName = parts.slice(1, patronymicNameIndex);
20976 			    } else {
20977 				    this.givenName = parts.slice(0, patronymicNameIndex);
20978 
20979 				    this.familyName = parts[parts.length - 1];
20980 			    }
20981 		    } else {
20982 			    this.givenName = parts[0];
20983 
20984 			    this.middleName = parts.slice(1, parts.length - 1);
20985 
20986 			    this.familyName = parts[parts.length - 1];
20987 		    }
20988 	    }
20989     },
20990     
20991     
20992     /**
20993      * @protected
20994      */
20995     _parseWesternName: function (parts) {
20996 
20997         if (this.locale.getLanguage() === "es" || this.locale.getLanguage() === "pt") {
20998             // in spain and mexico and portugal, we parse names differently than in the rest of the world 
20999             // because of the double family names
21000             this._parseSpanishName(parts);
21001         } else if (this.locale.getLanguage() === "ru") {
21002             /*
21003              * In Russian, names can be given equally validly as given-family
21004              * or family-given. Use the value of the "order" property of the
21005              * constructor options to give the default when the order is ambiguous.
21006              */
21007             this._parseRussianName(parts);
21008         } else if (this.locale.getLanguage() === "id") {
21009             // in indonesia, we parse names differently than in the rest of the world 
21010             // because names don't have family names usually.
21011             this._parseIndonesianName(parts);
21012         } else {
21013         	this._parseGenericWesternName(parts);
21014         }
21015     },
21016 
21017     /**
21018      * When sorting names with auxiliary words (like "van der" or "de los"), determine
21019      * which is the "head word" and return a string that can be easily sorted by head
21020      * word. In English, names are always sorted by initial characters. In places like
21021      * the Netherlands or Germany, family names are sorted by the head word of a list
21022      * of names rather than the first element of that name.
21023      * @return {string|undefined} a string containing the family name[s] to be used for sorting
21024      * in the current locale, or undefined if there is no family name in this object
21025      */
21026     getSortFamilyName: function () {
21027         var name,
21028             auxillaries,
21029             auxString,
21030             parts,
21031             i;
21032 
21033         // no name to sort by
21034         if (!this.familyName) {
21035             return undefined;
21036         }
21037 
21038         // first break the name into parts
21039         if (this.info) {
21040             if (this.info.sortByHeadWord) {
21041                 if (typeof (this.familyName) === 'string') {
21042                     name = this.familyName.replace(/\s+/g, ' '); // compress multiple whitespaces
21043                     parts = name.trim().split(' ');
21044                 } else {
21045                     // already split
21046                     parts = this.familyName;
21047                 }
21048 
21049                 auxillaries = this._findPrefix(parts, this.info.auxillaries, false);
21050                 if (auxillaries && auxillaries.length > 0) {
21051                     if (typeof (this.familyName) === 'string') {
21052                         auxString = auxillaries.join(' ');
21053                         name = this.familyName.substring(auxString.length + 1) + ', ' + auxString;
21054                     } else {
21055                         name = parts.slice(auxillaries.length).join(' ') +
21056                             ', ' +
21057                             parts.slice(0, auxillaries.length).join(' ');
21058                     }
21059                 }
21060             } else if (this.info.knownFamilyNames && this.familyName) {
21061                 parts = this.familyName.split('');
21062                 var familyNameArray = this._findPrefix(parts, this.info.knownFamilyNames, true, this.info.noCompoundFamilyNames);
21063                 name = "";
21064                 for (i = 0; i < familyNameArray.length; i++) {
21065                     name += (this.info.knownFamilyNames[familyNameArray[i]] || "");
21066                 }
21067             }
21068         }
21069 
21070         return name || this.familyName;
21071     },
21072 
21073     getHeadFamilyName: function () {},
21074 
21075     /** 
21076      * @protected
21077      * Return a shallow copy of the current instance.
21078      */
21079     clone: function () {
21080         return new Name(this);
21081     }
21082 };
21083 
21084 
21085 /*< NameFmt.js */
21086 /*
21087  * NameFmt.js - Format person names for display
21088  * 
21089  * Copyright © 2013-2015, JEDLSoft
21090  *
21091  * Licensed under the Apache License, Version 2.0 (the "License");
21092  * you may not use this file except in compliance with the License.
21093  * You may obtain a copy of the License at
21094  *
21095  *     http://www.apache.org/licenses/LICENSE-2.0
21096  *
21097  * Unless required by applicable law or agreed to in writing, software
21098  * distributed under the License is distributed on an "AS IS" BASIS,
21099  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21100  *
21101  * See the License for the specific language governing permissions and
21102  * limitations under the License.
21103  */
21104 
21105 /* !depends 
21106 ilib.js
21107 Locale.js
21108 IString.js
21109 Name.js
21110 isPunct.js
21111 Utils.js
21112 */
21113 
21114 // !data name
21115 
21116 
21117 
21118 
21119 /**
21120  * @class
21121  * Creates a formatter that can format person name instances (Name) for display to
21122  * a user. The options may contain the following properties:
21123  * 
21124  * <ul>
21125  * <li><i>locale</i> - Use the conventions of the given locale to construct the name format. 
21126  * <li><i>style</i> - Format the name with the given style. The value of this property
21127  * should be one of the following strings: 
21128  *   <ul>
21129  *     <li><i>short</i> - Format a short name with just the given and family names.
21130  *     <li><i>medium</i> - Format a medium-length name with the given, middle, and family names.
21131  *     <li><i>long</i> - Format a long name with all names available in the given name object, including
21132  *     prefixes.
21133  *     <li><i>full</i> - Format a long name with all names available in the given name object, including
21134  *     prefixes and suffixes.
21135  *   </ul>
21136  * <li><i>components</i> - Format the name with the given components in the correct
21137  * order for those components. Components are encoded as a string of letters representing
21138  * the desired components:
21139  *   <ul>
21140  *     <li><i>p</i> - prefixes
21141  *     <li><i>g</i> - given name
21142  *     <li><i>m</i> - middle names
21143  *     <li><i>f</i> - family name
21144  *     <li><i>s</i> - suffixes
21145  *   </ul>
21146  * <p>
21147  * 
21148  * For example, the string "pf" would mean to only format any prefixes and family names 
21149  * together and leave out all the other parts of the name.<p>
21150  * 
21151  * The components can be listed in any order in the string. The <i>components</i> option 
21152  * overrides the <i>style</i> option if both are specified.
21153  *
21154  * <li>onLoad - a callback function to call when the locale info object is fully 
21155  * loaded. When the onLoad option is given, the localeinfo object will attempt to
21156  * load any missing locale data using the ilib loader callback.
21157  * When the constructor is done (even if the data is already preassembled), the 
21158  * onLoad function is called with the current instance as a parameter, so this
21159  * callback can be used with preassembled or dynamic loading or a mix of the two.
21160  * 
21161  * <li>sync - tell whether to load any missing locale data synchronously or 
21162  * asynchronously. If this option is given as "false", then the "onLoad"
21163  * callback must be given, as the instance returned from this constructor will
21164  * not be usable for a while. 
21165  *
21166  * <li><i>loadParams</i> - an object containing parameters to pass to the 
21167  * loader callback function when locale data is missing. The parameters are not
21168  * interpretted or modified in any way. They are simply passed along. The object 
21169  * may contain any property/value pairs as long as the calling code is in
21170  * agreement with the loader callback function as to what those parameters mean.
21171  * </ul>
21172  * 
21173  * Formatting names is a locale-dependent function, as the order of the components 
21174  * depends on the locale. The following explains some of the details:<p>
21175  * 
21176  * <ul>
21177  * <li>In Western countries, the given name comes first, followed by a space, followed 
21178  * by the family name. In Asian countries, the family name comes first, followed immediately
21179  * by the given name with no space. But, that format is only used with Asian names written
21180  * in ideographic characters. In Asian countries, especially ones where both an Asian and 
21181  * a Western language are used (Hong Kong, Singapore, etc.), the convention is often to 
21182  * follow the language of the name. That is, Asian names are written in Asian style, and 
21183  * Western names are written in Western style. This class follows that convention as
21184  * well. 
21185  * <li>In other Asian countries, Asian names
21186  * written in Latin script are written with Asian ordering. eg. "Xu Ping-an" instead
21187  * of the more Western order "Ping-an Xu", as the order is thought to go with the style
21188  * that is appropriate for the name rather than the style for the language being written.
21189  * <li>In some Spanish speaking countries, people often take both their maternal and
21190  * paternal last names as their own family name. When formatting a short or medium style
21191  * of that family name, only the paternal name is used. In the long style, all the names
21192  * are used. eg. "Juan Julio Raul Lopez Ortiz" took the name "Lopez" from his father and 
21193  * the name "Ortiz" from his mother. His family name would be "Lopez Ortiz". The formatted
21194  * short style of his name would be simply "Juan Lopez" which only uses his paternal
21195  * family name of "Lopez".
21196  * <li>In many Western languages, it is common to use auxillary words in family names. For
21197  * example, the family name of "Ludwig von Beethoven" in German is "von Beethoven", not 
21198  * "Beethoven". This class ensures that the family name is formatted correctly with 
21199  * all auxillary words.   
21200  * </ul>
21201  * 
21202  * 
21203  * @constructor
21204  * @param {Object} options A set of options that govern how the formatter will behave
21205  */
21206 var NameFmt = function(options) {
21207 	var sync = true;
21208 	
21209 	this.style = "short";
21210 	this.loadParams = {};
21211 	
21212 	if (options) {
21213 		if (options.locale) {
21214 			this.locale = (typeof(options.locale) === 'string') ? new Locale(options.locale) : options.locale;
21215 		}
21216 		
21217 		if (options.style) {
21218 			this.style = options.style;
21219 		}
21220 		
21221 		if (options.components) {
21222 			this.components = options.components;
21223 		}
21224 		
21225 		if (typeof(options.sync) !== 'undefined') {
21226 			sync = (options.sync == true);
21227 		}
21228 		
21229 		if (typeof(options.loadParams) !== 'undefined') {
21230 			this.loadParams = options.loadParams;
21231 		}
21232 	}
21233 	
21234 	// set up defaults in case we need them
21235 	this.defaultEuroTemplate = new IString("{prefix} {givenName} {middleName} {familyName}{suffix}");
21236 	this.defaultAsianTemplate = new IString("{prefix}{familyName}{givenName}{middleName}{suffix}");
21237 	this.useFirstFamilyName = false;
21238 
21239 	switch (this.style) {
21240 		default:
21241 		case "s":
21242 		case "short":
21243 			this.style = "short";
21244 			break;
21245 		case "m":
21246 		case "medium":
21247 			this.style = "medium";
21248 			break;
21249 		case "l":
21250 		case "long":
21251 			this.style = "long";
21252 			break;
21253 		case "f":
21254 		case "full":
21255 			this.style = "full";
21256 			break;
21257 	}
21258 
21259 	if (!Name.cache) {
21260 		Name.cache = {};
21261 	}
21262 
21263 	this.locale = this.locale || new Locale();
21264 	
21265 	isPunct._init(sync, this.loadParams, ilib.bind(this, function() {
21266 		Utils.loadData({
21267 			object: Name, 
21268 			locale: this.locale, 
21269 			name: "name.json", 
21270 			sync: sync, 
21271 			loadParams: this.loadParams, 
21272 			callback: ilib.bind(this, function (info) {
21273 				if (!info) {
21274 					info = Name.defaultInfo;
21275 					var spec = this.locale.getSpec().replace(/-/g, "_");
21276 					Name.cache[spec] = info;
21277 				}
21278 				this.info = info;
21279 				this._init();
21280 				if (options && typeof(options.onLoad) === 'function') {
21281 					options.onLoad(this);
21282 				}
21283 			})
21284 		});
21285 	}));
21286 };
21287 
21288 NameFmt.prototype = {
21289 	/**                          
21290 	 * @protected
21291 	 */
21292 	_init: function() {
21293 		if (this.components) {
21294 			var valids = {"p":1,"g":1,"m":1,"f":1,"s":1},
21295 				arr = this.components.split("");
21296 			this.comps = {};
21297 			for (var i = 0; i < arr.length; i++) {
21298 				if (valids[arr[i].toLowerCase()]) {
21299 					this.comps[arr[i].toLowerCase()] = true;
21300 				}
21301 			}
21302 		} else {
21303 			this.comps = this.info.components[this.style];
21304 		}
21305 
21306 		this.template = new IString(this.info.format);
21307 		
21308 		if (this.locale.language === "es" && (this.style !== "long" && this.style !== "full")) {
21309 			this.useFirstFamilyName = true;	// in spanish, they have 2 family names, the maternal and paternal
21310 		}
21311 
21312 		this.isAsianLocale = (this.info.nameStyle === "asian");
21313 	},
21314 
21315 	/**
21316 	 * adjoin auxillary words to their head words
21317 	 * @protected
21318 	 */
21319 	_adjoinAuxillaries: function (parts, namePrefix) {
21320 		var start, i, prefixArray, prefix, prefixLower;
21321 		
21322 		//console.info("_adjoinAuxillaries: finding and adjoining aux words in " + parts.join(' '));
21323 		
21324 		if ( this.info.auxillaries && (parts.length > 2 || namePrefix) ) {
21325 			for ( start = 0; start < parts.length-1; start++ ) {
21326 				for ( i = parts.length; i > start; i-- ) {
21327 					prefixArray = parts.slice(start, i);
21328 					prefix = prefixArray.join(' ');
21329 					prefixLower = prefix.toLowerCase();
21330 					prefixLower = prefixLower.replace(/[,\.]/g, '');  // ignore commas and periods
21331 					
21332 					//console.info("_adjoinAuxillaries: checking aux prefix: '" + prefixLower + "' which is " + start + " to " + i);
21333 					
21334 					if ( prefixLower in this.info.auxillaries ) {
21335 						//console.info("Found! Old parts list is " + JSON.stringify(parts));
21336 						parts.splice(start, i+1-start, prefixArray.concat(parts[i]));
21337 						//console.info("_adjoinAuxillaries: Found! New parts list is " + JSON.stringify(parts));
21338 						i = start;
21339 					}
21340 				}
21341 			}
21342 		}
21343 		
21344 		//console.info("_adjoinAuxillaries: done. Result is " + JSON.stringify(parts));
21345 
21346 		return parts;
21347 	},
21348 
21349 	/**
21350 	 * Return the locale for this formatter instance.
21351 	 * @return {Locale} the locale instance for this formatter
21352 	 */
21353 	getLocale: function () {
21354 		return this.locale;
21355 	},
21356 	
21357 	/**
21358 	 * Return the style of names returned by this formatter
21359 	 * @return {string} the style of names returned by this formatter
21360 	 */
21361 	getStyle: function () {
21362 		return this.style;
21363 	},
21364 	
21365 	/**
21366 	 * Return the list of components used to format names in this formatter
21367 	 * @return {string} the list of components
21368 	 */
21369 	getComponents: function () {
21370 		return this.components;
21371 	},
21372 	
21373 	/**
21374 	 * Format the name for display in the current locale with the options set up
21375 	 * in the constructor of this formatter instance.<p>
21376 	 * 
21377 	 * If the name does not contain all the parts required for the style, those parts
21378 	 * will be left blank.<p>
21379 	 * 
21380 	 * There are two basic styles of formatting: European, and Asian. If this formatter object
21381 	 * is set for European style, but an Asian name is passed to the format method, then this
21382 	 * method will format the Asian name with a generic Asian template. Similarly, if the
21383 	 * formatter is set for an Asian style, and a European name is passed to the format method,
21384 	 * the formatter will use a generic European template.<p>
21385 	 * 
21386 	 * This means it is always safe to format any name with a formatter for any locale. You should
21387 	 * always get something at least reasonable as output.<p>
21388 	 * 
21389 	 * @param {Name} name the name to format
21390 	 * @return {string|undefined} the name formatted according to the style of this formatter instance
21391 	 */
21392 	format: function(name) {
21393 		var formatted, temp, modified, isAsianName;
21394 		var currentLanguage = this.locale.getLanguage();
21395 		 
21396 		if (!name || typeof(name) !== 'object') {
21397 			return undefined;
21398 		}
21399 		
21400 		if ((typeof(name.isAsianName) === 'boolean' && !name.isAsianName) ||
21401 				Name._isEuroName([name.givenName, name.middleName, name.familyName].join(""), currentLanguage)) {
21402 			isAsianName = false;	// this is a euro name, even if the locale is asian
21403 			modified = name.clone();
21404 			
21405 			// handle the case where there is no space if there is punctuation in the suffix like ", Phd". 
21406 			// Otherwise, put a space in to transform "PhD" to " PhD"
21407 			/*
21408 			console.log("suffix is " + modified.suffix);
21409 			if ( modified.suffix ) {
21410 				console.log("first char is " + modified.suffix.charAt(0));
21411 				console.log("isPunct(modified.suffix.charAt(0)) is " + isPunct(modified.suffix.charAt(0)));
21412 			}
21413 			*/
21414 			if (modified.suffix && isPunct(modified.suffix.charAt(0)) === false) {
21415 				modified.suffix = ' ' + modified.suffix; 
21416 			}
21417 			
21418 			if (this.useFirstFamilyName && name.familyName) {
21419 				var familyNameParts = modified.familyName.trim().split(' ');
21420 				if (familyNameParts.length > 1) {
21421 					familyNameParts = this._adjoinAuxillaries(familyNameParts, name.prefix);
21422 				}	//in spain and mexico, we parse names differently than in the rest of the world
21423 	
21424 				modified.familyName = familyNameParts[0];
21425 			}
21426 		
21427 			modified._joinNameArrays();
21428 		} else {
21429 			isAsianName = true;
21430 			modified = name;
21431 			if (modified.suffix && currentLanguage === "ko" && this.info.honorifics.indexOf(name.suffix) == -1) {
21432 				modified.suffix = ' ' + modified.suffix; 
21433 			}
21434 		}
21435 		
21436 		if (!this.template || isAsianName !== this.isAsianLocale) {
21437 			temp = isAsianName ? this.defaultAsianTemplate : this.defaultEuroTemplate;
21438 		} else {
21439 			temp = this.template;
21440 		}
21441 		
21442 		var parts = {
21443 			prefix: this.comps["p"] && modified.prefix || "",
21444 			givenName: this.comps["g"] && modified.givenName || "",
21445 			middleName: this.comps["m"] && modified.middleName || "",
21446 			familyName: this.comps["f"] && modified.familyName || "",
21447 			suffix: this.comps["s"] && modified.suffix || ""
21448 		};
21449 		
21450 		formatted = temp.format(parts);
21451 		return formatted.replace(/\s+/g, ' ').trim();
21452 	}
21453 };
21454 
21455 
21456 /*< Address.js */
21457 /*
21458  * Address.js - Represent a mailing address
21459  * 
21460  * Copyright © 2013-2015, JEDLSoft
21461  *
21462  * Licensed under the Apache License, Version 2.0 (the "License");
21463  * you may not use this file except in compliance with the License.
21464  * You may obtain a copy of the License at
21465  *
21466  *     http://www.apache.org/licenses/LICENSE-2.0
21467  *
21468  * Unless required by applicable law or agreed to in writing, software
21469  * distributed under the License is distributed on an "AS IS" BASIS,
21470  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21471  *
21472  * See the License for the specific language governing permissions and
21473  * limitations under the License.
21474  */
21475 
21476 /*globals console RegExp */
21477 
21478 /* !depends 
21479 ilib.js
21480 Utils.js
21481 JSUtils.js
21482 Locale.js 
21483 isIdeo.js 
21484 isAscii.js
21485 isDigit.js
21486 IString.js
21487 */
21488 
21489 // !data address countries nativecountries ctrynames
21490 
21491 
21492 /**
21493  * @class
21494  * Create a new Address instance and parse a physical address.<p>
21495  * 
21496  * This function parses a physical address written in a free-form string. 
21497  * It returns an object with a number of properties from the list below 
21498  * that it may have extracted from that address.<p>
21499  * 
21500  * The following is a list of properties that the algorithm will return:<p>
21501  * 
21502  * <ul>
21503  * <li><i>streetAddress</i>: The street address, including house numbers and all.
21504  * <li><i>locality</i>: The locality of this address (usually a city or town). 
21505  * <li><i>region</i>: The region where the locality is located. In the US, this
21506  * corresponds to states. In other countries, this may be provinces,
21507  * cantons, prefectures, etc. In some smaller countries, there are no
21508  * such divisions.
21509  * <li><i>postalCode</i>: Country-specific code for expediting mail. In the US, 
21510  * this is the zip code.
21511  * <li><i>country</i>: The country of the address.
21512  * <li><i>countryCode</i>: The ISO 3166 2-letter region code for the destination
21513  * country in this address.
21514  * </ul> 
21515  * 
21516  * The above properties will not necessarily appear in the instance. For 
21517  * any individual property, if the free-form address does not contain 
21518  * that property or it cannot be parsed out, the it is left out.<p>
21519  * 
21520  * The options parameter may contain any of the following properties:
21521  * 
21522  * <ul>
21523  * <li><i>locale</i> - locale or localeSpec to use to parse the address. If not 
21524  * specified, this function will use the current ilib locale
21525  * 
21526  * <li><i>onLoad</i> - a callback function to call when the address info for the
21527  * locale is fully loaded and the address has been parsed. When the onLoad 
21528  * option is given, the address object 
21529  * will attempt to load any missing locale data using the ilib loader callback.
21530  * When the constructor is done (even if the data is already preassembled), the 
21531  * onLoad function is called with the current instance as a parameter, so this
21532  * callback can be used with preassembled or dynamic loading or a mix of the two. 
21533  * 
21534  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
21535  * asynchronously. If this option is given as "false", then the "onLoad"
21536  * callback must be given, as the instance returned from this constructor will
21537  * not be usable for a while. 
21538  *
21539  * <li><i>loadParams</i> - an object containing parameters to pass to the 
21540  * loader callback function when locale data is missing. The parameters are not
21541  * interpretted or modified in any way. They are simply passed along. The object 
21542  * may contain any property/value pairs as long as the calling code is in
21543  * agreement with the loader callback function as to what those parameters mean.
21544  * </ul>
21545  * 
21546  * When an address cannot be parsed properly, the entire address will be placed
21547  * into the streetAddress property.<p>
21548  * 
21549  * When the freeformAddress is another Address, this will act like a copy
21550  * constructor.<p>
21551  * 
21552  * 
21553  * @constructor
21554  * @param {string|Address} freeformAddress free-form address to parse, or a
21555  * javascript object containing the fields
21556  * @param {Object} options options to the parser
21557  */
21558 var Address = function (freeformAddress, options) {
21559 	var address;
21560 
21561 	if (!freeformAddress) {
21562 		return undefined;
21563 	}
21564 
21565 	this.sync = true;
21566 	this.loadParams = {};
21567 	
21568 	if (options) {
21569 		if (options.locale) {
21570 			this.locale = (typeof(options.locale) === 'string') ? new Locale(options.locale) : options.locale;
21571 		}
21572 		
21573 		if (typeof(options.sync) !== 'undefined') {
21574 			this.sync = (options.sync == true);
21575 		}
21576 		
21577 		if (options.loadParams) {
21578 			this.loadParams = options.loadParams;
21579 		}
21580 	}
21581 
21582 	this.locale = this.locale || new Locale();
21583 	// initialize from an already parsed object
21584 	if (typeof(freeformAddress) === 'object') {
21585 		/**
21586 		 * The street address, including house numbers and all.
21587 		 * @type {string|undefined} 
21588 		 */
21589 		this.streetAddress = freeformAddress.streetAddress;
21590 		/**
21591 		 * The locality of this address (usually a city or town).
21592 		 * @type {string|undefined} 
21593 		 */
21594 		this.locality = freeformAddress.locality;
21595 		/**
21596 		 * The region (province, canton, prefecture, state, etc.) where the address is located.
21597 		 * @type {string|undefined} 
21598 		 */
21599 		this.region = freeformAddress.region;
21600 		/**
21601 		 * Country-specific code for expediting mail. In the US, this is the zip code.
21602 		 * @type {string|undefined} 
21603 		 */
21604 		this.postalCode = freeformAddress.postalCode;
21605 		/**
21606 		 * Optional city-specific code for a particular post office, used to expidite
21607 		 * delivery.
21608 		 * @type {string|undefined} 
21609 		 */
21610 		this.postOffice = freeformAddress.postOffice;
21611 		/**
21612 		 * The country of the address.
21613 		 * @type {string|undefined}
21614 		 */
21615 		this.country = freeformAddress.country;
21616 		if (freeformAddress.countryCode) {
21617 			/**
21618 			 * The 2 or 3 letter ISO 3166 region code for the destination country in this address.
21619 			 * @type {string} 
21620 			 */
21621 			this.countryCode = freeformAddress.countryCode;
21622 		}
21623 		if (freeformAddress.format) {
21624 			/**
21625 			 * private
21626 			 * @type {string}
21627 			 */
21628 			this.format = freeformAddress.format;
21629 		}
21630 		return this;
21631 	}
21632 
21633 	address = freeformAddress.replace(/[ \t\r]+/g, " ").trim();
21634 	address = address.replace(/[\s\n]+$/, "");
21635 	address = address.replace(/^[\s\n]+/, "");
21636 	//console.log("\n\n-------------\nAddress is '" + address + "'");
21637 	
21638 	this.lines = address.split(/[,,\n]/g);
21639 	this.removeEmptyLines(this.lines);
21640 	
21641 	isAscii._init(this.sync, this.loadParams, ilib.bind(this, function() {
21642 		isIdeo._init(this.sync, this.loadParams, ilib.bind(this, function() {
21643 			isDigit._init(this.sync, this.loadParams, ilib.bind(this, function() {
21644 				if (typeof(ilib.data.nativecountries) === 'undefined') {
21645 					Utils.loadData({
21646 						object: Address,
21647 						name: "nativecountries.json", // countries in their own language 
21648 						locale: "-", // only need to load the root file 
21649 						nonlocale: true,
21650 						sync: this.sync, 
21651 						loadParams: this.loadParams, 
21652 						callback: ilib.bind(this, function(nativecountries) {
21653 							ilib.data.nativecountries = nativecountries;
21654 							this._loadCountries(options && options.onLoad);
21655 						})
21656 					});
21657 				} else {
21658 					this._loadCountries(options && options.onLoad);
21659 				}
21660 			}));
21661 		}));
21662 	}));
21663 };
21664 
21665 /** @protected */
21666 Address.prototype = {
21667 	/**
21668 	 * @private
21669 	 */
21670 	_loadCountries: function(onLoad) {
21671 		if (typeof(ilib.data.countries) === 'undefined') {
21672 			Utils.loadData({
21673 				object: Address,
21674 				name: "countries.json", // countries in English
21675 				locale: "-", // only need to load the root file
21676 				nonlocale: true,
21677 				sync: this.sync, 
21678 				loadParams: this.loadParams, 
21679 				callback: ilib.bind(this, function(countries) {
21680 					ilib.data.countries = countries;
21681 					this._loadCtrynames(onLoad);
21682 				})
21683 			});
21684 		} else {
21685 			this._loadCtrynames(onLoad);
21686 		}
21687 	},
21688 
21689 	/**
21690 	 * @private
21691 	 */
21692 	_loadCtrynames: function(onLoad) {
21693 		Utils.loadData({
21694 			name: "ctrynames.json", 
21695 			object: Address, 
21696 			locale: this.locale,
21697 			sync: this.sync, 
21698 			loadParams: this.loadParams, 
21699 			callback: ilib.bind(this, function(ctrynames) {
21700 				this._determineDest(ctrynames, onLoad);
21701 			})
21702 		});
21703 	},
21704 	
21705 	/**
21706 	 * @private
21707 	 * @param {Object?} ctrynames
21708 	 */
21709 	_findDest: function (ctrynames) {
21710 		var match;
21711 		
21712 		for (var countryName in ctrynames) {
21713 			if (countryName && countryName !== "generated") {
21714 				// find the longest match in the current table
21715 				// ctrynames contains the country names mapped to region code
21716 				// for efficiency, only test for things longer than the current match
21717 				if (!match || match.text.length < countryName.length) {
21718 					var temp = this._findCountry(countryName);
21719 					if (temp) {
21720 						match = temp;
21721 						this.country = match.text;
21722 						this.countryCode = ctrynames[countryName];
21723 					}
21724 				}
21725 			}
21726 		}
21727 		return match;
21728 	},
21729 	
21730 	/**
21731 	 * @private
21732 	 * @param {Object?} localizedCountries
21733 	 * @param {function(Address):undefined} callback
21734 	 */
21735 	_determineDest: function (localizedCountries, callback) {
21736 		var match;
21737 		
21738 		/*
21739 		 * First, find the name of the destination country, as that determines how to parse
21740 		 * the rest of the address. For any address, there are three possible ways 
21741 		 * that the name of the country could be written:
21742 		 * 1. In the current language
21743 		 * 2. In its own native language
21744 		 * 3. In English
21745 		 * We'll try all three.
21746 		 */
21747 		var tables = [];
21748 		if (localizedCountries) {
21749 			tables.push(localizedCountries);
21750 		}
21751 		tables.push(ilib.data.nativecountries);
21752 		tables.push(ilib.data.countries);
21753 		
21754 		for (var i = 0; i < tables.length; i++) {
21755 			match = this._findDest(tables[i]);
21756 			
21757 			if (match) {
21758 				this.lines[match.line] = this.lines[match.line].substring(0, match.start) + this.lines[match.line].substring(match.start + match.text.length);
21759 
21760 				this._init(callback);
21761 				return;
21762 			}
21763 		}
21764 		
21765 		// no country, so try parsing it as if we were in the same country
21766 		this.country = undefined;
21767 		this.countryCode = this.locale.getRegion();
21768 		this._init(callback);
21769 	},
21770 
21771 	/**
21772 	 * @private
21773 	 * @param {function(Address):undefined} callback
21774 	 */
21775 	_init: function(callback) {
21776 		Utils.loadData({
21777 			object: Address, 
21778 			locale: new Locale(this.countryCode), 
21779 			name: "address.json", 
21780 			sync: this.sync, 
21781 			loadParams: this.loadParams,
21782 			callback: ilib.bind(this, function(info) {
21783 				if (!info || JSUtils.isEmpty(info)) {
21784 					// load the "unknown" locale instead
21785 					Utils.loadData({
21786 						object: Address, 
21787 						locale: new Locale("XX"), 
21788 						name: "address.json", 
21789 						sync: this.sync, 
21790 						loadParams: this.loadParams,
21791 						callback: ilib.bind(this, function(info) {
21792 							this.info = info;
21793 							this._parseAddress();
21794 							if (typeof(callback) === 'function') {
21795 								callback(this);
21796 							}	
21797 						})
21798 					});
21799 				} else {
21800 					this.info = info;
21801 					this._parseAddress();
21802 					if (typeof(callback) === 'function') {
21803 						callback(this);
21804 					}
21805 				}
21806 			})
21807 		});
21808 	},
21809 
21810 	/**
21811 	 * @private
21812 	 */
21813 	_parseAddress: function() {
21814 		// clean it up first
21815 		var i, 
21816 			asianChars = 0, 
21817 			latinChars = 0,
21818 			startAt,
21819 			infoFields,
21820 			field,
21821 			pattern,
21822 			matchFunction,
21823 			match,
21824 			fieldNumber;
21825 		
21826 		// for locales that support both latin and asian character addresses, 
21827 		// decide if we are parsing an asian or latin script address
21828 		if (this.info && this.info.multiformat) {
21829 			for (var j = 0; j < this.lines.length; j++) {
21830 				var line = new IString(this.lines[j]);
21831 				var it = line.charIterator();
21832 				while (it.hasNext()) {
21833 					var c = it.next();
21834 					if (isIdeo(c) || CType.withinRange(c, "Hangul")) {
21835 						asianChars++;
21836 					} else if (isAscii(c) && !isDigit(c)) {
21837 						latinChars++;
21838 					}
21839 				}
21840 			}
21841 			
21842 			this.format = (asianChars >= latinChars) ? "asian" : "latin";
21843 			startAt = this.info.startAt[this.format];
21844 			infoFields = this.info.fields[this.format];
21845 			// //console.log("multiformat locale: format is now " + this.format);
21846 		} else {
21847 			startAt = (this.info && this.info.startAt) || "end";
21848 			infoFields = this.info.fields;
21849 		}
21850 		this.compare = (startAt === "end") ? this.endsWith : this.startsWith;
21851 		
21852 		//console.log("this.lines is: " + JSON.stringify(this.lines));
21853 		
21854 		for (i = 0; i < infoFields.length && this.lines.length > 0; i++) {
21855 			field = infoFields[i];
21856 			this.removeEmptyLines(this.lines);
21857 			//console.log("Searching for field " + field.name);
21858 			if (field.pattern) {
21859 				if (typeof(field.pattern) === 'string') {
21860 					pattern = new RegExp(field.pattern, "img");
21861 					matchFunction = this.matchRegExp;
21862 				} else {
21863 					pattern = field.pattern;
21864 					matchFunction = this.matchPattern;
21865 				}
21866 					
21867 				switch (field.line) {
21868 				case 'startAtFirst':
21869 					for (fieldNumber = 0; fieldNumber < this.lines.length; fieldNumber++) {
21870 						match = matchFunction(this, this.lines[fieldNumber], pattern, field.matchGroup, startAt);
21871 						if (match) {
21872 							break;
21873 						}
21874 					}
21875 					break;
21876 				case 'startAtLast':
21877 					for (fieldNumber = this.lines.length-1; fieldNumber >= 0; fieldNumber--) {
21878 						match = matchFunction(this, this.lines[fieldNumber], pattern, field.matchGroup, startAt);
21879 						if (match) {
21880 							break;
21881 						}
21882 					}
21883 					break;
21884 				case 'first':
21885 					fieldNumber = 0;
21886 					match = matchFunction(this, this.lines[fieldNumber], pattern, field.matchGroup, startAt);
21887 					break;
21888 				case 'last':
21889 				default:
21890 					fieldNumber = this.lines.length - 1;
21891 					match = matchFunction(this, this.lines[fieldNumber], pattern, field.matchGroup, startAt);
21892 					break;
21893 				}
21894 				if (match) {
21895 					// //console.log("found match for " + field.name + ": " + JSON.stringify(match));
21896 					// //console.log("remaining line is " + match.line);
21897 					this.lines[fieldNumber] = match.line;
21898 					this[field.name] = match.match;
21899 				}
21900 			} else {
21901 				// if nothing is given, default to taking the whole field
21902 				this[field.name] = this.lines.splice(fieldNumber,1)[0].trim();
21903 				//console.log("typeof(this[field.name]) is " + typeof(this[field.name]) + " and value is " + JSON.stringify(this[field.name]));
21904 			}
21905 		}
21906 			
21907 		// all the left overs go in the street address field
21908 		this.removeEmptyLines(this.lines);
21909 		if (this.lines.length > 0) {
21910 			//console.log("this.lines is " + JSON.stringify(this.lines) + " and splicing to get streetAddress");
21911 			// Korea uses spaces between words, despite being an "asian" locale
21912 			var joinString = (this.info.joinString && this.info.joinString[this.format]) || ((this.format && this.format === "asian") ? "" : ", ");
21913 			this.streetAddress = this.lines.join(joinString).trim();
21914 		}
21915 		
21916 		this.lines = undefined;
21917 		//console.log("final result is " + JSON.stringify(this));
21918 	},
21919 	
21920 	/**
21921 	 * @protected
21922 	 * Find the named country either at the end or the beginning of the address.
21923 	 */
21924 	_findCountry: function(name) {
21925 		var start = -1, match, line = 0;
21926 		
21927 		if (this.lines.length > 0) {
21928 			start = this.startsWith(this.lines[line], name);
21929 			if (start === -1) {
21930 				line = this.lines.length-1;
21931 				start = this.endsWith(this.lines[line], name);
21932 			}
21933 			if (start !== -1) {
21934 				match = {
21935 					text: this.lines[line].substring(start, start + name.length),
21936 					line: line,
21937 					start: start
21938 				};
21939 			}
21940 		}
21941 		
21942 		return match;
21943 	},
21944 	
21945 	endsWith: function (subject, query) {
21946 		var start = subject.length-query.length,
21947 			i,
21948 			pat;
21949 		//console.log("endsWith: checking " + query + " against " + subject);
21950 		for (i = 0; i < query.length; i++) {
21951 			// TODO: use case mapper instead of toLowerCase()
21952 			if (subject.charAt(start+i).toLowerCase() !== query.charAt(i).toLowerCase()) {
21953 				return -1;
21954 			}
21955 		}
21956 		if (start > 0) {
21957 			pat = /\s/;
21958 			if (!pat.test(subject.charAt(start-1))) {
21959 				// make sure if we are not at the beginning of the string, that the match is 
21960 				// not the end of some other word
21961 				return -1;
21962 			}
21963 		}
21964 		return start;
21965 	},
21966 	
21967 	startsWith: function (subject, query) {
21968 		var i;
21969 		// //console.log("startsWith: checking " + query + " against " + subject);
21970 		for (i = 0; i < query.length; i++) {
21971 			// TODO: use case mapper instead of toLowerCase()
21972 			if (subject.charAt(i).toLowerCase() !== query.charAt(i).toLowerCase()) {
21973 				return -1;
21974 			}
21975 		}
21976 		return 0;
21977 	},
21978 	
21979 	removeEmptyLines: function (arr) {
21980 		var i = 0;
21981 		
21982 		while (i < arr.length) {
21983 			if (arr[i]) {
21984 				arr[i] = arr[i].trim();
21985 				if (arr[i].length === 0) {
21986 					arr.splice(i,1);
21987 				} else {
21988 					i++;
21989 				}
21990 			} else {
21991 				arr.splice(i,1);
21992 			}
21993 		}
21994 	},
21995 	
21996 	matchRegExp: function(address, line, expression, matchGroup, startAt) {
21997 		var lastMatch,
21998 			match,
21999 			ret = {},
22000 			last;
22001 		
22002 		//console.log("searching for regexp " + expression.source + " in line " + line);
22003 		
22004 		match = expression.exec(line);
22005 		if (startAt === 'end') {
22006 			while (match !== null && match.length > 0) {
22007 				//console.log("found matches " + JSON.stringify(match));
22008 				lastMatch = match;
22009 				match = expression.exec(line);
22010 			}
22011 			match = lastMatch;
22012 		}
22013 		
22014 		if (match && match !== null) {
22015 			//console.log("found matches " + JSON.stringify(match));
22016 			matchGroup = matchGroup || 0;
22017 			if (match[matchGroup] !== undefined) {
22018 				ret.match = match[matchGroup].trim();
22019 				ret.match = ret.match.replace(/^\-|\-+$/, '');
22020 				ret.match = ret.match.replace(/\s+$/, '');
22021 				last = (startAt === 'end') ? line.lastIndexOf(match[matchGroup]) : line.indexOf(match[matchGroup]); 
22022 				//console.log("last is " + last);
22023 				ret.line = line.slice(0,last);
22024 				if (address.format !== "asian") {
22025 					ret.line += " ";
22026 				}
22027 				ret.line += line.slice(last+match[matchGroup].length);
22028 				ret.line = ret.line.trim();
22029 				//console.log("found match " + ret.match + " from matchgroup " + matchGroup + " and rest of line is " + ret.line);
22030 				return ret;
22031 			}
22032 		//} else {
22033 			//console.log("no match");
22034 		}
22035 		
22036 		return undefined;
22037 	},
22038 	
22039 	matchPattern: function(address, line, pattern, matchGroup) {
22040 		var start,
22041 			j,
22042 			ret = {};
22043 		
22044 		//console.log("searching in line " + line);
22045 		
22046 		// search an array of possible fixed strings
22047 		//console.log("Using fixed set of strings.");
22048 		for (j = 0; j < pattern.length; j++) {
22049 			start = address.compare(line, pattern[j]); 
22050 			if (start !== -1) {
22051                             ret.match = line.substring(start, start+pattern[j].length);
22052                             if (start !== 0) {
22053                                 ret.line = line.substring(0,start).trim();
22054                             } else {
22055                                 ret.line = line.substring(pattern[j].length).trim();
22056                             }
22057 				//console.log("found match " + ret.match + " and rest of line is " + ret.line);
22058                             return ret;
22059 			}
22060 		}
22061 		
22062 		return undefined;
22063 	}
22064 };
22065 
22066 
22067 
22068 /*< AddressFmt.js */
22069 /*
22070  * AddressFmt.js - Format an address
22071  * 
22072  * Copyright © 2013-2015, JEDLSoft
22073  *
22074  * Licensed under the Apache License, Version 2.0 (the "License");
22075  * you may not use this file except in compliance with the License.
22076  * You may obtain a copy of the License at
22077  *
22078  *     http://www.apache.org/licenses/LICENSE-2.0
22079  *
22080  * Unless required by applicable law or agreed to in writing, software
22081  * distributed under the License is distributed on an "AS IS" BASIS,
22082  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22083  *
22084  * See the License for the specific language governing permissions and
22085  * limitations under the License.
22086  */
22087 
22088 /* !depends 
22089 ilib.js 
22090 Locale.js
22091 Address.js
22092 IString.js
22093 Utils.js
22094 JSUtils.js
22095 */
22096 
22097 // !data address
22098 
22099 
22100 
22101 /**
22102  * @class
22103  * Create a new formatter object to format physical addresses in a particular way.
22104  *
22105  * The options object may contain the following properties, both of which are optional:
22106  *
22107  * <ul>
22108  * <li><i>locale</i> - the locale to use to format this address. If not specified, it uses the default locale
22109  * 
22110  * <li><i>style</i> - the style of this address. The default style for each country usually includes all valid 
22111  * fields for that country.
22112  * 
22113  * <li><i>onLoad</i> - a callback function to call when the address info for the
22114  * locale is fully loaded and the address has been parsed. When the onLoad 
22115  * option is given, the address formatter object 
22116  * will attempt to load any missing locale data using the ilib loader callback.
22117  * When the constructor is done (even if the data is already preassembled), the 
22118  * onLoad function is called with the current instance as a parameter, so this
22119  * callback can be used with preassembled or dynamic loading or a mix of the two. 
22120  * 
22121  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
22122  * asynchronously. If this option is given as "false", then the "onLoad"
22123  * callback must be given, as the instance returned from this constructor will
22124  * not be usable for a while. 
22125  *
22126  * <li><i>loadParams</i> - an object containing parameters to pass to the 
22127  * loader callback function when locale data is missing. The parameters are not
22128  * interpretted or modified in any way. They are simply passed along. The object 
22129  * may contain any property/value pairs as long as the calling code is in
22130  * agreement with the loader callback function as to what those parameters mean.
22131  * </ul>
22132  * 
22133  * 
22134  * @constructor
22135  * @param {Object} options options that configure how this formatter should work
22136  * Returns a formatter instance that can format multiple addresses.
22137  */
22138 var AddressFmt = function(options) {
22139 	this.sync = true;
22140 	this.styleName = 'default';
22141 	this.loadParams = {};
22142 	this.locale = new Locale();
22143 	
22144 	if (options) {
22145 		if (options.locale) {
22146 			this.locale = (typeof(options.locale) === 'string') ? new Locale(options.locale) : options.locale;
22147 		}
22148 		
22149 		if (typeof(options.sync) !== 'undefined') {
22150 			this.sync = (options.sync == true);
22151 		}
22152 		
22153 		if (options.style) {
22154 			this.styleName = options.style;
22155 		}
22156 		
22157 		if (options.loadParams) {
22158 			this.loadParams = options.loadParams;
22159 		}
22160 	}
22161 	
22162 	// console.log("Creating formatter for region: " + this.locale.region);
22163 	Utils.loadData({
22164 		name: "address.json",
22165 		object: AddressFmt, 
22166 		locale: this.locale,
22167 		sync: this.sync, 
22168 		loadParams: this.loadParams, 
22169 		callback: ilib.bind(this, function(info) {
22170 			if (!info || JSUtils.isEmpty(info)) {
22171 				// load the "unknown" locale instead
22172 				Utils.loadData({
22173 					name: "address.json",
22174 					object: AddressFmt, 
22175 					locale: new Locale("XX"),
22176 					sync: this.sync, 
22177 					loadParams: this.loadParams, 
22178 					callback: ilib.bind(this, function(info) {
22179 						this.info = info;
22180 						this._init();
22181 						if (options && typeof(options.onLoad) === 'function') {
22182 							options.onLoad(this);
22183 						}
22184 					})
22185 				});
22186 			} else {
22187 				this.info = info;
22188 				this._init();
22189 				if (options && typeof(options.onLoad) === 'function') {
22190 					options.onLoad(this);
22191 				}
22192 			}
22193 		})
22194 	});
22195 };
22196 
22197 /**
22198  * @private
22199  */
22200 AddressFmt.prototype._init = function () {
22201 	this.style = this.info && this.info.formats && this.info.formats[this.styleName];
22202 	
22203 	// use generic default -- should not happen, but just in case...
22204 	this.style = this.style || (this.info && this.info.formats["default"]) || "{streetAddress}\n{locality} {region} {postalCode}\n{country}";
22205 };
22206 
22207 /**
22208  * This function formats a physical address (Address instance) for display. 
22209  * Whitespace is trimmed from the beginning and end of final resulting string, and 
22210  * multiple consecutive whitespace characters in the middle of the string are 
22211  * compressed down to 1 space character.
22212  * 
22213  * If the Address instance is for a locale that is different than the locale for this
22214  * formatter, then a hybrid address is produced. The country name is located in the
22215  * correct spot for the current formatter's locale, but the rest of the fields are
22216  * formatted according to the default style of the locale of the actual address.
22217  * 
22218  * Example: a mailing address in China, but formatted for the US might produce the words
22219  * "People's Republic of China" in English at the last line of the address, and the 
22220  * Chinese-style address will appear in the first line of the address. In the US, the
22221  * country is on the last line, but in China the country is usually on the first line.
22222  *
22223  * @param {Address} address Address to format
22224  * @returns {string} Returns a string containing the formatted address
22225  */
22226 AddressFmt.prototype.format = function (address) {
22227 	var ret, template, other, format;
22228 	
22229 	if (!address) {
22230 		return "";
22231 	}
22232 	// console.log("formatting address: " + JSON.stringify(address));
22233 	if (address.countryCode && 
22234 			address.countryCode !== this.locale.region && 
22235 			Locale._isRegionCode(this.locale.region) && 
22236 			this.locale.region !== "XX") {
22237 		// we are formatting an address that is sent from this country to another country,
22238 		// so only the country should be in this locale, and the rest should be in the other
22239 		// locale
22240 		// console.log("formatting for another locale. Loading in its settings: " + address.countryCode);
22241 		other = new AddressFmt({
22242 			locale: new Locale(address.countryCode), 
22243 			style: this.styleName
22244 		});
22245 		return other.format(address);
22246 	}
22247 	
22248 	if (typeof(this.style) === 'object') {
22249 		format = this.style[address.format || "latin"];
22250 	} else {
22251 		format = this.style;
22252 	}
22253 	
22254 	// console.log("Using format: " + format);
22255 	// make sure we have a blank string for any missing parts so that
22256 	// those template parts get blanked out
22257 	var params = {
22258 		country: address.country || "",
22259 		region: address.region || "",
22260 		locality: address.locality || "",
22261 		streetAddress: address.streetAddress || "",
22262 		postalCode: address.postalCode || "",
22263 		postOffice: address.postOffice || ""
22264 	};
22265 	template = new IString(format);
22266 	ret = template.format(params);
22267 	ret = ret.replace(/[ \t]+/g, ' ');
22268 	ret = ret.replace("\n ", "\n");
22269 	ret = ret.replace(" \n", "\n");
22270 	return ret.replace(/\n+/g, '\n').trim();
22271 };
22272 
22273 
22274 
22275 /*< GlyphString.js */
22276 /*
22277  * GlyphString.js - ilib string subclass that allows you to access 
22278  * whole glyphs at a time
22279  * 
22280  * Copyright © 2015, JEDLSoft
22281  *
22282  * Licensed under the Apache License, Version 2.0 (the "License");
22283  * you may not use this file except in compliance with the License.
22284  * You may obtain a copy of the License at
22285  *
22286  *     http://www.apache.org/licenses/LICENSE-2.0
22287  *
22288  * Unless required by applicable law or agreed to in writing, software
22289  * distributed under the License is distributed on an "AS IS" BASIS,
22290  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22291  *
22292  * See the License for the specific language governing permissions and
22293  * limitations under the License.
22294  */
22295 
22296 // !depends IString.js CType.js Utils.js JSUtils.js
22297 // !data norm ctype_m
22298 
22299 
22300 
22301 /**
22302  * @class
22303  * Create a new glyph string instance. This string inherits from 
22304  * the IString class, and adds methods that allow you to access
22305  * whole glyphs at a time. <p>
22306  * 
22307  * In Unicode, various accented characters can be created by using
22308  * a base character and one or more combining characters following
22309  * it. These appear on the screen to the user as a single glyph.
22310  * For example, the Latin character "a" (U+0061) followed by the
22311  * combining diaresis character "¨" (U+0308) combine together to
22312  * form the "a with diaresis" glyph "ä", which looks like a single
22313  * character on the screen.<p>
22314  * 
22315  * The big problem with combining characters for web developers is
22316  * that many CSS engines do not ellipsize text between glyphs. They
22317  * only deal with single Unicode characters. So if a particular space 
22318  * only allows for 4 characters, the CSS engine will truncate a
22319  * string at 4 Unicode characters and then add the ellipsis (...)
22320  * character. What if the fourth Unicode character is the "a" and
22321  * the fifth one is the diaresis? Then a string like "xxxäxxx" that
22322  * is ellipsized at 4 characters will appear as "xxxa..." on the 
22323  * screen instead of "xxxä...".<p>
22324  * 
22325  * In the Latin script as it is commonly used, it is not so common
22326  * to form accented characters using combining accents, so the above
22327  * example is mostly for illustrative purposes. It is not unheard of
22328  * however. The situation is much, much worse in scripts such as Thai and 
22329  * Devanagari that normally make very heavy use of combining characters.
22330  * These scripts do so because Unicode does not include pre-composed 
22331  * versions of the accented characters like it does for Latin, so 
22332  * combining accents are the only way to create these accented and 
22333  * combined versions of the characters.<p>
22334  * 
22335  * The solution to thise problem is not to use the the CSS property 
22336  * "text-overflow: ellipsis" in your web site, ever. Instead, use
22337  * a glyph string to truncate text between glyphs instead of between
22338  * characters.<p>
22339  * 
22340  * Glyph strings are also useful for truncation, hyphenation, and 
22341  * line wrapping, as all of these should be done between glyphs instead
22342  * of between characters.<p>
22343  * 
22344  * The options parameter is optional, and may contain any combination
22345  * of the following properties:<p>
22346  * 
22347  * <ul>
22348  * <li><i>onLoad</i> - a callback function to call when the locale data are
22349  * fully loaded. When the onLoad option is given, this object will attempt to
22350  * load any missing locale data using the ilib loader callback.
22351  * When the constructor is done (even if the data is already preassembled), the 
22352  * onLoad function is called with the current instance as a parameter, so this
22353  * callback can be used with preassembled or dynamic loading or a mix of the two.
22354  * 
22355  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
22356  * asynchronously. If this option is given as "false", then the "onLoad"
22357  * callback must be given, as the instance returned from this constructor will
22358  * not be usable for a while.
22359  *  
22360  * <li><i>loadParams</i> - an object containing parameters to pass to the 
22361  * loader callback function when locale data is missing. The parameters are not
22362  * interpretted or modified in any way. They are simply passed along. The object 
22363  * may contain any property/value pairs as long as the calling code is in
22364  * agreement with the loader callback function as to what those parameters mean.
22365  * </ul>
22366  * 
22367  * @constructor
22368  * @extends IString
22369  * @param {string|IString=} str initialize this instance with this string 
22370  * @param {Object=} options options governing the way this instance works
22371  */
22372 var GlyphString = function (str, options) {
22373 	if (options && options.noinstance) {
22374 		return;
22375 	}
22376 	
22377 	IString.call(this, str);
22378 	
22379 	var sync = true;
22380 	var loadParams = {};
22381 	if (options) {
22382 		if (typeof(options.sync) === 'boolean') {
22383 			sync = options.sync;
22384 		}
22385 		if (options.loadParams) {
22386 			loadParams = options.loadParams;
22387 		}
22388 	}
22389 	
22390 	CType._load("ctype_m", sync, loadParams, function() {
22391 		if (!ilib.data.norm || JSUtils.isEmpty(ilib.data.norm.ccc)) {
22392 			Utils.loadData({
22393 				object: GlyphString, 
22394 				locale: "-", 
22395 				name: "normdata.json",
22396 				nonlocale: true,
22397 				sync: sync, 
22398 				loadParams: loadParams, 
22399 				callback: ilib.bind(this, function (norm) {
22400 					ilib.extend(ilib.data.norm, norm);
22401 					if (options && typeof(options.onLoad) === 'function') {
22402 						options.onLoad(this);
22403 					}
22404 				})
22405 			});
22406 		} else {
22407 			if (options && typeof(options.onLoad) === 'function') {
22408 				options.onLoad(this);
22409 			}
22410 		}
22411 	});
22412 };
22413 
22414 GlyphString.prototype = new IString(undefined);
22415 GlyphString.prototype.parent = IString;
22416 GlyphString.prototype.constructor = GlyphString;
22417 
22418 /**
22419  * Return true if the given character is a leading Jamo (Choseong) character.
22420  * 
22421  * @private
22422  * @static
22423  * @param {number} n code point to check
22424  * @return {boolean} true if the character is a leading Jamo character, 
22425  * false otherwise
22426  */
22427 GlyphString._isJamoL = function (n) {
22428 	return (n >= 0x1100 && n <= 0x1112);
22429 };
22430 
22431 /**
22432  * Return true if the given character is a vowel Jamo (Jungseong) character.
22433  * 
22434  * @private
22435  * @static
22436  * @param {number} n code point to check
22437  * @return {boolean} true if the character is a vowel Jamo character, 
22438  * false otherwise
22439  */
22440 GlyphString._isJamoV = function (n) {
22441 	return (n >= 0x1161 && n <= 0x1175);
22442 };
22443 
22444 /**
22445  * Return true if the given character is a trailing Jamo (Jongseong) character.
22446  * 
22447  * @private
22448  * @static
22449  * @param {number} n code point to check
22450  * @return {boolean} true if the character is a trailing Jamo character, 
22451  * false otherwise
22452  */
22453 GlyphString._isJamoT = function (n) {
22454 	return (n >= 0x11A8 && n <= 0x11C2);
22455 };
22456 
22457 /**
22458  * Return true if the given character is a precomposed Hangul character.
22459  * 
22460  * @private
22461  * @static
22462  * @param {number} n code point to check
22463  * @return {boolean} true if the character is a precomposed Hangul character, 
22464  * false otherwise
22465  */
22466 GlyphString._isHangul = function (n) {
22467 	return (n >= 0xAC00 && n <= 0xD7A3);
22468 };
22469 
22470 /**
22471  * Algorithmically compose an L and a V combining Jamo characters into
22472  * a precomposed Korean syllabic Hangul character. Both should already
22473  * be in the proper ranges for L and V characters. 
22474  * 
22475  * @private
22476  * @static
22477  * @param {number} lead the code point of the lead Jamo character to compose
22478  * @param {number} trail the code point of the trailing Jamo character to compose
22479  * @return {string} the composed Hangul character
22480  */
22481 GlyphString._composeJamoLV = function (lead, trail) {
22482 	var lindex = lead - 0x1100;
22483 	var vindex = trail - 0x1161;
22484 	return IString.fromCodePoint(0xAC00 + (lindex * 21 + vindex) * 28);
22485 };
22486 
22487 /**
22488  * Algorithmically compose a Hangul LV and a combining Jamo T character 
22489  * into a precomposed Korean syllabic Hangul character. 
22490  * 
22491  * @private
22492  * @static
22493  * @param {number} lead the code point of the lead Hangul character to compose
22494  * @param {number} trail the code point of the trailing Jamo T character to compose
22495  * @return {string} the composed Hangul character
22496  */
22497 GlyphString._composeJamoLVT = function (lead, trail) {
22498 	return IString.fromCodePoint(lead + (trail - 0x11A7));
22499 };
22500 
22501 /**
22502  * Compose one character out of a leading character and a 
22503  * trailing character. If the characters are Korean Jamo, they
22504  * will be composed algorithmically. If they are any other
22505  * characters, they will be looked up in the nfc tables.
22506  * 
22507  * @private
22508  * @static
22509  * @param {string} lead leading character to compose
22510  * @param {string} trail the trailing character to compose
22511  * @return {string|null} the fully composed character, or undefined if
22512  * there is no composition for those two characters
22513  */
22514 GlyphString._compose = function (lead, trail) {
22515 	var first = lead.charCodeAt(0);
22516 	var last = trail.charCodeAt(0);
22517 	if (GlyphString._isHangul(first) && GlyphString._isJamoT(last)) {
22518 		return GlyphString._composeJamoLVT(first, last);
22519 	} else if (GlyphString._isJamoL(first) && GlyphString._isJamoV(last)) {
22520 		return GlyphString._composeJamoLV(first, last);
22521 	}
22522 
22523 	var c = lead + trail;
22524 	return (ilib.data.norm.nfc && ilib.data.norm.nfc[c]);
22525 };
22526 
22527 /**
22528  * Return an iterator that will step through all of the characters
22529  * in the string one at a time, taking care to step through decomposed 
22530  * characters and through surrogate pairs in the UTF-16 encoding 
22531  * as single characters. <p>
22532  * 
22533  * The GlyphString class will return decomposed Unicode characters
22534  * as a single unit that a user might see on the screen as a single
22535  * glyph. If the 
22536  * next character in the iteration is a base character and it is 
22537  * followed by combining characters, the base and all its following 
22538  * combining characters are returned as a single unit.<p>
22539  * 
22540  * The standard Javascript String's charAt() method only
22541  * returns information about a particular 16-bit character in the 
22542  * UTF-16 encoding scheme.
22543  * If the index is pointing to a low- or high-surrogate character,
22544  * it will return that surrogate character rather 
22545  * than the surrogate pair which represents a character 
22546  * in the supplementary planes.<p>
22547  * 
22548  * The iterator instance returned has two methods, hasNext() which
22549  * returns true if the iterator has more characters to iterate through,
22550  * and next() which returns the next character.<p>
22551  * 
22552  * @override
22553  * @return {Object} an iterator 
22554  * that iterates through all the characters in the string
22555  */
22556 GlyphString.prototype.charIterator = function() {
22557 	var it = IString.prototype.charIterator.call(this);
22558 	
22559 	/**
22560 	 * @constructor
22561 	 */
22562 	function _chiterator (istring) {
22563 		this.index = 0;
22564 		this.spacingCombining = false;
22565 		this.hasNext = function () {
22566 			return !!this.nextChar || it.hasNext();
22567 		};
22568 		this.next = function () {
22569 			var ch = this.nextChar || it.next(),
22570 				prevCcc = ilib.data.norm.ccc[ch],
22571 				nextCcc,
22572 				composed = ch;
22573 			
22574 			this.nextChar = undefined;
22575 			this.spacingCombining = false;
22576 			
22577 			if (ilib.data.norm.ccc && 
22578 					(typeof(ilib.data.norm.ccc[ch]) === 'undefined' || ilib.data.norm.ccc[ch] === 0)) {
22579 				// found a starter... find all the non-starters until the next starter. Must include
22580 				// the next starter because under some odd circumstances, two starters sometimes recompose 
22581 				// together to form another character
22582 				var notdone = true;
22583 				while (it.hasNext() && notdone) {
22584 					this.nextChar = it.next();
22585 					nextCcc = ilib.data.norm.ccc[this.nextChar];
22586 					var codePoint = IString.toCodePoint(this.nextChar, 0);
22587 					// Mn characters are Marks that are non-spacing. These do not take more room than an accent, so they should be 
22588 					// considered part of the on-screen glyph, even if they are non-combining. Mc are marks that are spacing
22589 					// and combining, which means they are part of the glyph, but they cause the glyph to use up more space than
22590 					// just the base character alone.
22591 					var isMn = CType._inRange(codePoint, "Mn", ilib.data.ctype_m);
22592 					var isMc = CType._inRange(codePoint, "Mc", ilib.data.ctype_m);
22593 					if (isMn || isMc || (typeof(nextCcc) !== 'undefined' && nextCcc !== 0)) {
22594 						if (isMc) {
22595 							this.spacingCombining = true;
22596 						}
22597 						ch += this.nextChar;
22598 						this.nextChar = undefined;
22599 					} else {
22600 						// found the next starter. See if this can be composed with the previous starter
22601 						var testChar = GlyphString._compose(composed, this.nextChar);
22602 						if (prevCcc === 0 && typeof(testChar) !== 'undefined') { 
22603 							// not blocked and there is a mapping 
22604 							composed = testChar;
22605 							ch += this.nextChar;
22606 							this.nextChar = undefined;
22607 						} else {
22608 							// finished iterating, leave this.nextChar for the next next() call 
22609 							notdone = false;
22610 						}
22611 					}
22612 					prevCcc = nextCcc;
22613 				}
22614 			}
22615 			return ch;
22616 		};
22617 		// Returns true if the last character returned by the "next" method included
22618 		// spacing combining characters. If it does, then the character was wider than
22619 		// just the base character alone, and the truncation code will not add it.
22620 		this.wasSpacingCombining = function() {
22621 			return this.spacingCombining;
22622 		};
22623 	};
22624 	return new _chiterator(this);
22625 };
22626 
22627 /**
22628  * Truncate the current string at the given number of whole glyphs and return
22629  * the resulting string.
22630  * 
22631  * @param {number} length the number of whole glyphs to keep in the string
22632  * @return {string} a string truncated to the requested number of glyphs
22633  */
22634 GlyphString.prototype.truncate = function(length) {
22635 	var it = this.charIterator();
22636 	var tr = "";
22637 	for (var i = 0; i < length-1 && it.hasNext(); i++) {
22638 		tr += it.next();
22639 	}
22640 	
22641 	/*
22642 	 * handle the last character separately. If it contains spacing combining
22643 	 * accents, then we must assume that it uses up more horizontal space on
22644 	 * the screen than just the base character by itself, and therefore this
22645 	 * method will not truncate enough characters to fit in the given length.
22646 	 * In this case, we have to chop off not only the combining characters, 
22647 	 * but also the base character as well because the base without the
22648 	 * combining accents is considered a different character.
22649 	 */
22650 	if (i < length && it.hasNext()) {
22651 		var c = it.next();
22652 		if (!it.wasSpacingCombining()) {
22653 			tr += c;
22654 		}
22655 	}
22656 	return tr;
22657 };
22658 
22659 /**
22660  * Truncate the current string at the given number of glyphs and add an ellipsis
22661  * to indicate that is more to the string. The ellipsis forms the last character
22662  * in the string, so the string is actually truncated at length-1 glyphs.
22663  * 
22664  * @param {number} length the number of whole glyphs to keep in the string 
22665  * including the ellipsis
22666  * @return {string} a string truncated to the requested number of glyphs
22667  * with an ellipsis
22668  */
22669 GlyphString.prototype.ellipsize = function(length) {
22670 	return this.truncate(length > 0 ? length-1 : 0) + "…";
22671 };
22672 
22673 
22674 
22675 /*< NormString.js */
22676 /*
22677  * NormString.js - ilib normalized string subclass definition
22678  * 
22679  * Copyright © 2013-2015, JEDLSoft
22680  *
22681  * Licensed under the Apache License, Version 2.0 (the "License");
22682  * you may not use this file except in compliance with the License.
22683  * You may obtain a copy of the License at
22684  *
22685  *     http://www.apache.org/licenses/LICENSE-2.0
22686  *
22687  * Unless required by applicable law or agreed to in writing, software
22688  * distributed under the License is distributed on an "AS IS" BASIS,
22689  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22690  *
22691  * See the License for the specific language governing permissions and
22692  * limitations under the License.
22693  */
22694 
22695 // !depends IString.js GlyphString.js Utils.js
22696 
22697 
22698 
22699 /**
22700  * @class
22701  * Create a new normalized string instance. This string inherits from 
22702  * the GlyphString class, and adds the normalize method. It can be
22703  * used anywhere that a normal Javascript string is used. <p>
22704  * 
22705  * 
22706  * @constructor
22707  * @extends GlyphString
22708  * @param {string|IString=} str initialize this instance with this string 
22709  */
22710 var NormString = function (str) {
22711 	GlyphString.call(this, str);
22712 };
22713 
22714 NormString.prototype = new GlyphString("", {noinstance:true});
22715 NormString.prototype.parent = GlyphString;
22716 NormString.prototype.constructor = NormString;
22717 
22718 /**
22719  * Initialize the normalized string routines statically. This
22720  * is intended to be called in a dynamic-load version of ilib
22721  * to load the data need to normalize strings before any instances
22722  * of NormString are created.<p>
22723  * 
22724  * The options parameter may contain any of the following properties:
22725  * 
22726  * <ul>
22727  * <li><i>form</i> - {string} the normalization form to load
22728  * <li><i>script</i> - {string} load the normalization for this script. If the 
22729  * script is given as "all" then the normalization data for all scripts
22730  * is loaded at the same time
22731  * <li><i>sync</i> - {boolean} whether to load the files synchronously or not
22732  * <li><i>loadParams</i> - {Object} parameters to the loader function
22733  * <li><i>onLoad</i> - {function()} a function to call when the 
22734  * files are done being loaded
22735  * </ul>
22736  * 
22737  * @param {Object} options an object containing properties that govern 
22738  * how to initialize the data
22739  */
22740 NormString.init = function(options) {
22741 	if (!ilib._load || (typeof(ilib._load) !== 'function' && typeof(ilib._load.loadFiles) !== 'function')) {
22742 		// can't do anything
22743 		return;
22744 	}
22745 	var form = "nfkc";
22746 	var script = "all";
22747 	var sync = true;
22748 	var onLoad = undefined;
22749 	var loadParams = undefined;
22750 	if (options) {
22751 		form = options.form || "nfkc";
22752 		script = options.script || "all";
22753 		sync = typeof(options.sync) !== 'undefined' ? options.sync : true;
22754 		onLoad = typeof(options.onLoad) === 'function' ? options.onLoad : undefined;
22755 		if (options.loadParams) {
22756 			loadParams = options.loadParams;
22757 		}
22758 	}
22759 	var formDependencies = {
22760 		"nfd": ["nfd"],
22761 		"nfc": ["nfd"],
22762 		"nfkd": ["nfkd", "nfd"],
22763 		"nfkc": ["nfkd", "nfd"]
22764 	};
22765 	var files = ["normdata.json"];
22766 	var forms = formDependencies[form];
22767 	for (var f in forms) {
22768 		files.push(forms[f] + "/" + script + ".json");
22769 	}
22770 	
22771 	if (JSUtils.isEmpty(ilib.data.norm.ccc) || JSUtils.isEmpty(ilib.data.norm.nfd) || JSUtils.isEmpty(ilib.data.norm.nfkd)) {
22772 		//console.log("loading files " + JSON.stringify(files));
22773 		Utils._callLoadData(files, sync, loadParams, function(arr) {
22774 			ilib.extend(ilib.data.norm, arr[0]);
22775 			for (var i = 1; i < arr.length; i++) {
22776 				if (typeof(arr[i]) !== 'undefined') {
22777 					ilib.extend(ilib.data.norm[forms[i-1]], arr[i]);
22778 				}
22779 			}
22780 			
22781 			if (onLoad) {
22782 				onLoad(arr);
22783 			}
22784 		});
22785 	}
22786 };
22787 
22788 /**
22789  * Algorithmically decompose a precomposed Korean syllabic Hangul 
22790  * character into its individual combining Jamo characters. The given 
22791  * character must be in the range of Hangul characters U+AC00 to U+D7A3.
22792  * 
22793  * @private
22794  * @static
22795  * @param {number} cp code point of a Korean Hangul character to decompose
22796  * @return {string} the decomposed string of Jamo characters
22797  */
22798 NormString._decomposeHangul = function (cp) {
22799 	var sindex = cp - 0xAC00;
22800 	var result = String.fromCharCode(0x1100 + sindex / 588) + 
22801 			String.fromCharCode(0x1161 + (sindex % 588) / 28);
22802 	var t = sindex % 28;
22803 	if (t !== 0) {
22804 		result += String.fromCharCode(0x11A7 + t);
22805 	}
22806 	return result;
22807 };
22808 
22809 /**
22810  * Expand one character according to the given canonical and 
22811  * compatibility mappings.
22812  *
22813  * @private
22814  * @static
22815  * @param {string} ch character to map
22816  * @param {Object} canon the canonical mappings to apply
22817  * @param {Object=} compat the compatibility mappings to apply, or undefined
22818  * if only the canonical mappings are needed
22819  * @return {string} the mapped character
22820  */
22821 NormString._expand = function (ch, canon, compat) {
22822 	var i, 
22823 		expansion = "",
22824 		n = ch.charCodeAt(0);
22825 	if (GlyphString._isHangul(n)) {
22826 		expansion = NormString._decomposeHangul(n);
22827 	} else {
22828 		var result = canon[ch];
22829 		if (!result && compat) {
22830 			result = compat[ch];
22831 		}
22832 		if (result && result !== ch) {
22833 			for (i = 0; i < result.length; i++) {
22834 				expansion += NormString._expand(result[i], canon, compat);
22835 			}
22836 		} else {
22837 			expansion = ch;
22838 		}
22839 	}
22840 	return expansion;
22841 };
22842 
22843 /**
22844  * Perform the Unicode Normalization Algorithm upon the string and return 
22845  * the resulting new string. The current string is not modified.
22846  * 
22847  * <h2>Forms</h2>
22848  * 
22849  * The forms of possible normalizations are defined by the <a 
22850  * href="http://www.unicode.org/reports/tr15/">Unicode Standard
22851  * Annex (UAX) 15</a>. The form parameter is a string that may have one 
22852  * of the following values:
22853  * 
22854  * <ul>
22855  * <li>nfd - Canonical decomposition. This decomposes characters into
22856  * their exactly equivalent forms. For example, "ü" would decompose
22857  * into a "u" followed by the combining diaeresis character. 
22858  * <li>nfc - Canonical decomposition followed by canonical composition.
22859  * This decomposes and then recomposes character into their shortest
22860  * exactly equivalent forms by recomposing as many combining characters
22861  * as possible. For example, "ü" followed by a combining 
22862  * macron character would decompose into a "u" followed by the combining 
22863  * macron characters the combining diaeresis character, and then be recomposed into
22864  * the u with macron and diaeresis "ṻ" character. The reason that
22865  * the "nfc" form decomposes and then recomposes is that combining characters
22866  * have a specific order under the Unicode Normalization Algorithm, and
22867  * partly composed characters such as the "ü" followed by combining
22868  * marks may change the order of the combining marks when decomposed and
22869  * recomposed.
22870  * <li>nfkd - Compatibility decomposition. This decomposes characters
22871  * into compatible forms that may not be exactly equivalent semantically,
22872  * as well as performing canonical decomposition as well.
22873  * For example, the "œ" ligature character decomposes to the two
22874  * characters "oe" because they are compatible even though they are not 
22875  * exactly the same semantically. 
22876  * <li>nfkc - Compatibility decomposition followed by canonical composition.
22877  * This decomposes characters into compatible forms, then recomposes
22878  * characters using the canonical composition. That is, it breaks down
22879  * characters into the compatible forms, and then recombines all combining
22880  * marks it can with their base characters. For example, the character
22881  * "ǽ" would be normalized to "aé" by first decomposing
22882  * the character into "a" followed by "e" followed by the combining acute accent
22883  * combining mark, and then recomposed to an "a" followed by the "e"
22884  * with acute accent.
22885  * </ul>
22886  * 
22887  * <h2>Operation</h2>
22888  * 
22889  * Two strings a and b can be said to be canonically equivalent if 
22890  * normalize(a) = normalize(b)
22891  * under the nfc normalization form. Two strings can be said to be compatible if
22892  * normalize(a) = normalize(b) under the nfkc normalization form.<p>
22893  * 
22894  * The canonical normalization is often used to see if strings are 
22895  * equivalent to each other, and thus is useful when implementing parsing 
22896  * algorithms or exact matching algorithms. It can also be used to ensure
22897  * that any string output produces a predictable sequence of characters.<p>
22898  * 
22899  * Compatibility normalization 
22900  * does not always preserve the semantic meaning of all the characters, 
22901  * although this is sometimes the behaviour that you are after. It is useful, 
22902  * for example, when doing searches of user-input against text in documents 
22903  * where the matches are supposed to "fuzzy". In this case, both the query
22904  * string and the document string would be mapped to their compatibility 
22905  * normalized forms, and then compared.<p>
22906  * 
22907  * Compatibility normalization also does not guarantee round-trip conversion
22908  * to and from legacy character sets as the normalization is "lossy". It is 
22909  * akin to doing a lower- or upper-case conversion on text -- after casing,
22910  * you cannot tell what case each character is in the original string. It is 
22911  * good for matching and searching, but it rarely good for output because some 
22912  * distinctions or meanings in the original text have been lost.<p>
22913  * 
22914  * Note that W3C normalization for HTML also escapes and unescapes
22915  * HTML character entities such as "&uuml;" for u with diaeresis. This
22916  * method does not do such escaping or unescaping. If normalization is required
22917  * for HTML strings with entities, unescaping should be performed on the string 
22918  * prior to calling this method.<p>
22919  * 
22920  * <h2>Data</h2>
22921  * 
22922  * Normalization requires a fair amount of mapping data, much of which you may 
22923  * not need for the characters expected in your texts. It is possible to assemble
22924  * a copy of ilib that saves space by only including normalization data for 
22925  * those scripts that you expect to encounter in your data.<p>
22926  * 
22927  * The normalization data is organized by normalization form and within there
22928  * by script. To include the normalization data for a particular script with
22929  * a particular normalization form, use the directive:
22930  * 
22931  * <pre><code>
22932  * !depends <form>/<script>.js
22933  * </code></pre>
22934  * 
22935  * Where <form> is the normalization form ("nfd", "nfc", "nfkd", or "nfkc"), and
22936  * <script> is the ISO 15924 code for the script you would like to
22937  * support. Example: to load in the NFC data for Cyrillic, you would use:
22938  * 
22939  * <pre><code>
22940  * !depends nfc/Cyrl.js
22941  * </code></pre>
22942  * 
22943  * Note that because certain normalization forms include others in their algorithm, 
22944  * their data also depends on the data for the other forms. For example, if you 
22945  * include the "nfc" data for a script, you will automatically get the "nfd" data 
22946  * for that same script as well because the NFC algorithm does NFD normalization 
22947  * first. Here are the dependencies:<p>
22948  * 
22949  * <ul>
22950  * <li>NFD -> no dependencies
22951  * <li>NFC -> NFD
22952  * <li>NFKD -> NFD
22953  * <li>NFKC -> NFKD, NFD, NFC
22954  * </ul>
22955  * 
22956  * A special value for the script dependency is "all" which will cause the data for 
22957  * all scripts
22958  * to be loaded for that normalization form. This would be useful if you know that
22959  * you are going to normalize a lot of multilingual text or cannot predict which scripts
22960  * will appear in the input. Because the NFKC form depends on all others, you can 
22961  * get all of the data for all forms automatically by depending on "nfkc/all.js".
22962  * Note that the normalization data for practically all script automatically depend
22963  * on data for the Common script (code "Zyyy") which contains all of the characters
22964  * that are commonly used in many different scripts. Examples of characters in the
22965  * Common script are the ASCII punctuation characters, or the ASCII Arabic 
22966  * numerals "0" through "9".<p>
22967  * 
22968  * By default, none of the data for normalization is automatically 
22969  * included in the preassembled iliball.js file. 
22970  * If you would like to normalize strings, you must assemble
22971  * your own copy of ilib and explicitly include the normalization data
22972  * for those scripts as per the instructions above. This normalization method will 
22973  * produce output, even without the normalization data. However, the output will be 
22974  * simply the same thing as its input for all scripts 
22975  * except Korean Hangul and Jamo, which are decomposed and recomposed 
22976  * algorithmically and therefore do not rely on data.<p>
22977  * 
22978  * If characters are encountered for which there are no normalization data, they
22979  * will be passed through to the output string unmodified.
22980  * 
22981  * @param {string} form The normalization form requested
22982  * @return {IString} a new instance of an IString that has been normalized
22983  * according to the requested form. The current instance is not modified.
22984  */
22985 NormString.prototype.normalize = function (form) {
22986 	var i;
22987 	
22988 	if (typeof(form) !== 'string' || this.str.length === 0) {
22989 		return new IString(this.str);
22990 	}
22991 	
22992 	var nfc = false,
22993 		nfkd = false;
22994 	
22995 	switch (form) {
22996 	default:
22997 		break;
22998 		
22999 	case "nfc":
23000 		nfc = true;
23001 		break;
23002 		
23003 	case "nfkd":
23004 		nfkd = true;
23005 		break;
23006 		
23007 	case "nfkc":
23008 		nfkd = true;
23009 		nfc = true;
23010 		break;
23011 	}
23012 
23013 	// decompose
23014 	var decomp = "";
23015 	
23016 	if (nfkd) {
23017 		var ch, it = IString.prototype.charIterator.call(this);
23018 		while (it.hasNext()) {
23019 			ch = it.next();
23020 			decomp += NormString._expand(ch, ilib.data.norm.nfd, ilib.data.norm.nfkd);
23021 		}
23022 	} else {
23023 		var ch, it = IString.prototype.charIterator.call(this);
23024 		while (it.hasNext()) {
23025 			ch = it.next();
23026 			decomp += NormString._expand(ch, ilib.data.norm.nfd);
23027 		}
23028 	}
23029 
23030 	// now put the combining marks in a fixed order by 
23031 	// sorting on the combining class
23032 	function compareByCCC(left, right) {
23033 		return ilib.data.norm.ccc[left] - ilib.data.norm.ccc[right]; 
23034 	}
23035 	
23036 	function ccc(c) {
23037 		return ilib.data.norm.ccc[c] || 0;
23038 	}
23039 
23040 	function sortChars(arr, comp) {
23041 		// qt/qml's Javascript engine re-arranges entries that are equal to
23042 		// each other. Technically, that is a correct behaviour, but it is
23043 		// not desirable. All the other engines leave equivalent entries
23044 		// where they are. This bubblesort emulates what the other engines
23045 		// do. Fortunately, the arrays we are sorting are a max of 5 or 6
23046 		// entries, so performance is not a big deal here.
23047 		if (ilib._getPlatform() === "qt") {
23048 			var tmp;
23049 			for (var i = arr.length-1; i > 0; i--) {
23050 				for (var j = 0; j < i; j++) {
23051 					if (comp(arr[j], arr[j+1]) > 0) {
23052 						tmp = arr[j];
23053 						arr[j] = arr[j+1];
23054 						arr[j+1] = tmp;
23055 					}
23056 				}
23057 			}
23058 			return arr;
23059 		} else {
23060 			return arr.sort(comp);
23061 		}
23062 	}
23063 		
23064 	var dstr = new IString(decomp);
23065 	var it = dstr.charIterator();
23066 	var cpArray = [];
23067 
23068 	// easier to deal with as an array of chars
23069 	while (it.hasNext()) {
23070 		cpArray.push(it.next());
23071 	}
23072 	
23073 	i = 0;
23074 	while (i < cpArray.length) {
23075 		if (typeof(ilib.data.norm.ccc[cpArray[i]]) !== 'undefined' && ccc(cpArray[i]) !== 0) {
23076 			// found a non-starter... rearrange all the non-starters until the next starter
23077 			var end = i+1;
23078 			while (end < cpArray.length &&
23079 					typeof(ilib.data.norm.ccc[cpArray[end]]) !== 'undefined' && 
23080 					ccc(cpArray[end]) !== 0) {
23081 				end++;
23082 			}
23083 			
23084 			// simple sort of the non-starter chars
23085 			if (end - i > 1) {
23086 				cpArray = cpArray.slice(0,i).concat(sortChars(cpArray.slice(i, end), compareByCCC), cpArray.slice(end));
23087 			}
23088 		}
23089 		i++;
23090 	}
23091 	
23092 	if (nfc) {
23093 		i = 0;
23094 		while (i < cpArray.length) {
23095 			if (typeof(ilib.data.norm.ccc[cpArray[i]]) === 'undefined' || ilib.data.norm.ccc[cpArray[i]] === 0) {
23096 				// found a starter... find all the non-starters until the next starter. Must include
23097 				// the next starter because under some odd circumstances, two starters sometimes recompose 
23098 				// together to form another character
23099 				var end = i+1;
23100 				var notdone = true;
23101 				while (end < cpArray.length && notdone) {
23102 					if (typeof(ilib.data.norm.ccc[cpArray[end]]) !== 'undefined' && 
23103 						ilib.data.norm.ccc[cpArray[end]] !== 0) {
23104 						if (ccc(cpArray[end-1]) < ccc(cpArray[end])) { 
23105 							// not blocked 
23106 							var testChar = GlyphString._compose(cpArray[i], cpArray[end]);
23107 							if (typeof(testChar) !== 'undefined') {
23108 								cpArray[i] = testChar;
23109 								
23110 								// delete the combining char
23111 								cpArray.splice(end,1);	
23112 								
23113 								// restart the iteration, just in case there is more to recompose with the new char
23114 								end = i;
23115 							}
23116 						}
23117 						end++;
23118 					} else {
23119 						// found the next starter. See if this can be composed with the previous starter
23120 						var testChar = GlyphString._compose(cpArray[i], cpArray[end]);
23121 						if (ccc(cpArray[end-1]) === 0 && typeof(testChar) !== 'undefined') { 
23122 							// not blocked and there is a mapping 
23123 							cpArray[i] = testChar;
23124 							
23125 							// delete the combining char
23126 							cpArray.splice(end,1);
23127 							
23128 							// restart the iteration, just in case there is more to recompose with the new char
23129 							end = i+1;
23130 						} else {
23131 							// finished iterating 
23132 							notdone = false;
23133 						}
23134 					}
23135 				}
23136 			}
23137 			i++;
23138 		}
23139 	}
23140 	
23141 	return new IString(cpArray.length > 0 ? cpArray.join("") : "");
23142 };
23143 	
23144 /**
23145  * @override
23146  * Return an iterator that will step through all of the characters
23147  * in the string one at a time, taking care to step through decomposed 
23148  * characters and through surrogate pairs in UTF-16 encoding 
23149  * properly. <p>
23150  * 
23151  * The NormString class will return decomposed Unicode characters
23152  * as a single unit that a user might see on the screen. If the 
23153  * next character in the iteration is a base character and it is 
23154  * followed by combining characters, the base and all its following 
23155  * combining characters are returned as a single unit.<p>
23156  * 
23157  * The standard Javascript String's charAt() method only
23158  * returns information about a particular 16-bit character in the 
23159  * UTF-16 encoding scheme.
23160  * If the index is pointing to a low- or high-surrogate character,
23161  * it will return that surrogate character rather 
23162  * than the surrogate pair which represents a character 
23163  * in the supplementary planes.<p>
23164  * 
23165  * The iterator instance returned has two methods, hasNext() which
23166  * returns true if the iterator has more characters to iterate through,
23167  * and next() which returns the next character.<p>
23168  * 
23169  * @return {Object} an iterator 
23170  * that iterates through all the characters in the string
23171  */
23172 NormString.prototype.charIterator = function() {
23173 	var it = IString.prototype.charIterator.call(this);
23174 	
23175 	/**
23176 	 * @constructor
23177 	 */
23178 	function _chiterator (istring) {
23179 		/**
23180 		 * @private
23181 		 */
23182 		var ccc = function(c) {
23183 			return ilib.data.norm.ccc[c] || 0;
23184 		};
23185 
23186 		this.index = 0;
23187 		this.hasNext = function () {
23188 			return !!this.nextChar || it.hasNext();
23189 		};
23190 		this.next = function () {
23191 			var ch = this.nextChar || it.next(),
23192 				prevCcc = ccc(ch),
23193 				nextCcc,
23194 				composed = ch;
23195 			
23196 			this.nextChar = undefined;
23197 			
23198 			if (ilib.data.norm.ccc && 
23199 					(typeof(ilib.data.norm.ccc[ch]) === 'undefined' || ccc(ch) === 0)) {
23200 				// found a starter... find all the non-starters until the next starter. Must include
23201 				// the next starter because under some odd circumstances, two starters sometimes recompose 
23202 				// together to form another character
23203 				var notdone = true;
23204 				while (it.hasNext() && notdone) {
23205 					this.nextChar = it.next();
23206 					nextCcc = ccc(this.nextChar);
23207 					if (typeof(ilib.data.norm.ccc[this.nextChar]) !== 'undefined' && nextCcc !== 0) {
23208 						ch += this.nextChar;
23209 						this.nextChar = undefined;
23210 					} else {
23211 						// found the next starter. See if this can be composed with the previous starter
23212 						var testChar = GlyphString._compose(composed, this.nextChar);
23213 						if (prevCcc === 0 && typeof(testChar) !== 'undefined') { 
23214 							// not blocked and there is a mapping 
23215 							composed = testChar;
23216 							ch += this.nextChar;
23217 							this.nextChar = undefined;
23218 						} else {
23219 							// finished iterating, leave this.nextChar for the next next() call 
23220 							notdone = false;
23221 						}
23222 					}
23223 					prevCcc = nextCcc;
23224 				}
23225 			}
23226 			return ch;
23227 		};
23228 	};
23229 	return new _chiterator(this);
23230 };
23231 
23232 
23233 /*< CodePointSource.js */
23234 /*
23235  * CodePointSource.js - Source of code points from a string
23236  * 
23237  * Copyright © 2013-2015, JEDLSoft
23238  *
23239  * Licensed under the Apache License, Version 2.0 (the "License");
23240  * you may not use this file except in compliance with the License.
23241  * You may obtain a copy of the License at
23242  *
23243  *     http://www.apache.org/licenses/LICENSE-2.0
23244  *
23245  * Unless required by applicable law or agreed to in writing, software
23246  * distributed under the License is distributed on an "AS IS" BASIS,
23247  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23248  *
23249  * See the License for the specific language governing permissions and
23250  * limitations under the License.
23251  */
23252 
23253 // !depends isPunct.js NormString.js
23254 
23255 
23256 /**
23257  * @class
23258  * Represents a buffered source of code points. The input string is first
23259  * normalized so that combining characters come out in a standardized order.
23260  * If the "ignorePunctuation" flag is turned on, then punctuation 
23261  * characters are skipped.
23262  * 
23263  * @constructor
23264  * @private
23265  * @param {NormString|string} str a string to get code points from
23266  * @param {boolean} ignorePunctuation whether or not to ignore punctuation
23267  * characters
23268  */
23269 var CodePointSource = function(str, ignorePunctuation) {
23270 	this.chars = [];
23271 	// first convert the string to a normalized sequence of characters
23272 	var s = (typeof(str) === "string") ? new NormString(str) : str;
23273 	this.it = s.charIterator();
23274 	this.ignorePunctuation = typeof(ignorePunctuation) === "boolean" && ignorePunctuation;
23275 };
23276 
23277 /**
23278  * Return the first num code points in the source without advancing the
23279  * source pointer. If there are not enough code points left in the
23280  * string to satisfy the request, this method will return undefined. 
23281  * 
23282  * @param {number} num the number of characters to peek ahead
23283  * @return {string|undefined} a string formed out of up to num code points from
23284  * the start of the string, or undefined if there are not enough character left
23285  * in the source to complete the request
23286  */
23287 CodePointSource.prototype.peek = function(num) {
23288 	if (num < 1) {
23289 		return undefined;
23290 	}
23291 	if (this.chars.length < num && this.it.hasNext()) {
23292 		for (var i = 0; this.chars.length < 4 && this.it.hasNext(); i++) {
23293 			var c = this.it.next();
23294 			if (c && !this.ignorePunctuation || !isPunct(c)) {
23295 				this.chars.push(c);
23296 			}
23297 		}
23298 	}
23299 	if (this.chars.length < num) {
23300 		return undefined;
23301 	}
23302 	return this.chars.slice(0, num).join("");
23303 };
23304 /**
23305  * Advance the source pointer by the given number of code points.
23306  * @param {number} num number of code points to advance
23307  */
23308 CodePointSource.prototype.consume = function(num) {
23309 	if (num > 0) {
23310 		this.peek(num); // for the iterator to go forward if needed
23311 		if (num < this.chars.length) {
23312 			this.chars = this.chars.slice(num);
23313 		} else {
23314 			this.chars = [];
23315 		}
23316 	}
23317 };
23318 
23319 
23320 
23321 /*< ElementIterator.js */
23322 /*
23323  * ElementIterator.js - Iterate through a list of collation elements
23324  * 
23325  * Copyright © 2013-2015, JEDLSoft
23326  *
23327  * Licensed under the Apache License, Version 2.0 (the "License");
23328  * you may not use this file except in compliance with the License.
23329  * You may obtain a copy of the License at
23330  *
23331  *     http://www.apache.org/licenses/LICENSE-2.0
23332  *
23333  * Unless required by applicable law or agreed to in writing, software
23334  * distributed under the License is distributed on an "AS IS" BASIS,
23335  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23336  *
23337  * See the License for the specific language governing permissions and
23338  * limitations under the License.
23339  */
23340 
23341 /**
23342  * @class
23343  * An iterator through a sequence of collation elements. This
23344  * iterator takes a source of code points, converts them into
23345  * collation elements, and allows the caller to get single
23346  * elements at a time.
23347  * 
23348  * @constructor
23349  * @private
23350  * @param {CodePointSource} source source of code points to 
23351  * convert to collation elements
23352  * @param {Object} map mapping from sequences of code points to
23353  * collation elements
23354  * @param {number} keysize size in bits of the collation elements
23355  */
23356 var ElementIterator = function (source, map, keysize) {
23357 	this.elements = [];
23358 	this.source = source;
23359 	this.map = map;
23360 	this.keysize = keysize;
23361 };
23362 
23363 /**
23364  * @private
23365  */
23366 ElementIterator.prototype._fillBuffer = function () {
23367 	var str = undefined;
23368 	
23369 	// peek ahead by up to 4 characters, which may combine
23370 	// into 1 or more collation elements
23371 	for (var i = 4; i > 0; i--) {
23372 		str = this.source.peek(i);
23373 		if (str && this.map[str]) {
23374 			this.elements = this.elements.concat(this.map[str]);
23375 			this.source.consume(i);
23376 			return;
23377 		}
23378 	}
23379 	
23380 	if (str) {
23381 		// no mappings for the first code point, so just use its
23382 		// Unicode code point as a proxy for its sort order. Shift
23383 		// it by the key size so that everything unknown sorts
23384 		// after things that have mappings
23385 		this.elements.push(str.charCodeAt(0) << this.keysize);
23386 		this.source.consume(1);
23387 	} else {
23388 		// end of the string
23389 		return undefined;
23390 	}
23391 };
23392 
23393 /**
23394  * Return true if there are more collation elements left to
23395  * iterate through.
23396  * @returns {boolean} true if there are more elements left to
23397  * iterate through, and false otherwise
23398  */
23399 ElementIterator.prototype.hasNext = function () {
23400 	if (this.elements.length < 1) {
23401 		this._fillBuffer();
23402 	}
23403 	return !!this.elements.length;
23404 };
23405 
23406 /**
23407  * Return the next collation element. If more than one collation 
23408  * element is generated from a sequence of code points 
23409  * (ie. an "expansion"), then this class will buffer the
23410  * other elements and return them on subsequent calls to 
23411  * this method.
23412  * 
23413  * @returns {number|undefined} the next collation element or
23414  * undefined for no more collation elements
23415  */
23416 ElementIterator.prototype.next = function () {
23417 	if (this.elements.length < 1) {
23418 		this._fillBuffer();
23419 	}
23420 	var ret = this.elements[0];
23421 	this.elements = this.elements.slice(1);
23422 	return ret;
23423 };
23424 
23425 
23426 
23427 /*< Collator.js */
23428 /*
23429  * Collator.js - Collation routines
23430  * 
23431  * Copyright © 2013-2015, JEDLSoft
23432  *
23433  * Licensed under the Apache License, Version 2.0 (the "License");
23434  * you may not use this file except in compliance with the License.
23435  * You may obtain a copy of the License at
23436  *
23437  *     http://www.apache.org/licenses/LICENSE-2.0
23438  *
23439  * Unless required by applicable law or agreed to in writing, software
23440  * distributed under the License is distributed on an "AS IS" BASIS,
23441  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23442  *
23443  * See the License for the specific language governing permissions and
23444  * limitations under the License.
23445  */
23446 
23447 /* !depends 
23448 Locale.js 
23449 ilib.js 
23450 INumber.js 
23451 isPunct.js 
23452 NormString.js 
23453 MathUtils.js 
23454 Utils.js
23455 JSUtils.js
23456 LocaleInfo.js 
23457 CodePointSource.js
23458 ElementIterator.js
23459 */
23460 
23461 // !data collation
23462 
23463 
23464 /**
23465  * @class
23466  * A class that implements a locale-sensitive comparator function 
23467  * for use with sorting function. The comparator function
23468  * assumes that the strings it is comparing contain Unicode characters
23469  * encoded in UTF-16.<p>
23470  * 
23471  * Collations usually depend only on the language, because most collation orders 
23472  * are shared between locales that speak the same language. There are, however, a
23473  * number of instances where a locale collates differently than other locales
23474  * that share the same language. There are also a number of instances where a
23475  * locale collates differently based on the script used. This object can handle
23476  * these cases automatically if a full locale is specified in the options rather
23477  * than just a language code.<p>
23478  * 
23479  * <h2>Options</h2>
23480  * 
23481  * The options parameter can contain any of the following properties:
23482  * 
23483  * <ul>
23484  * <li><i>locale</i> - String|Locale. The locale which the comparator function 
23485  * will collate with. Default: the current iLib locale.
23486  * 
23487  * <li><i>sensitivity</i> - String. Sensitivity or strength of collator. This is one of 
23488  * "primary", "base", "secondary", "accent", "tertiary", "case", "quaternary", or 
23489  * "variant". Default: "primary"
23490  *   <ol>
23491  *   <li>base or primary - Only the primary distinctions between characters are significant.
23492  *   Another way of saying that is that the collator will be case-, accent-, and 
23493  *   variation-insensitive, and only distinguish between the base characters
23494  *   <li>case or secondary - Both the primary and secondary distinctions between characters
23495  *   are significant. That is, the collator will be accent- and variation-insensitive
23496  *   and will distinguish between base characters and character case.
23497  *   <li>accent or tertiary - The primary, secondary, and tertiary distinctions between
23498  *   characters are all significant. That is, the collator will be 
23499  *   variation-insensitive, but accent-, case-, and base-character-sensitive. 
23500  *   <li>variant or quaternary - All distinctions between characters are significant. That is,
23501  *   the algorithm is base character-, case-, accent-, and variation-sensitive.
23502  *   </ol>
23503  *   
23504  * <li><i>upperFirst</i> - boolean. When collating case-sensitively in a script that
23505  * has the concept of case, put upper-case
23506  * characters first, otherwise lower-case will come first. Warning: some browsers do
23507  * not implement this feature or at least do not implement it properly, so if you are 
23508  * using the native collator with this option, you may get different results in different
23509  * browsers. To guarantee the same results, set useNative to false to use the ilib 
23510  * collator implementation. This of course will be somewhat slower, but more 
23511  * predictable. Default: true
23512  * 
23513  * <li><i>reverse</i> - boolean. Return the list sorted in reverse order. When the
23514  * upperFirst option is also set to true, upper-case characters would then come at 
23515  * the end of the list. Default: false.
23516  * 
23517  * <li><i>scriptOrder</i> - string. When collating strings in multiple scripts,
23518  * this property specifies what order those scripts should be sorted. The default
23519  * Unicode Collation Algorithm (UCA) already has a default order for scripts, but
23520  * this can be tailored via this property. The value of this option is a 
23521  * space-separated list of ISO 15924 scripts codes. If a code is specified in this
23522  * property, its default data must be included using the JS assembly tool. If the
23523  * data is not included, the ordering for the script will be ignored. Default:
23524  * the default order defined by the UCA. 
23525  * 
23526  * <li><i>style</i> - The value of the style parameter is dependent on the locale.
23527  * For some locales, there are different styles of collating strings depending
23528  * on what kind of strings are being collated or what the preference of the user 
23529  * is. For example, in German, there is a phonebook order and a dictionary ordering
23530  * that sort the same array of strings slightly differently.
23531  * The static method {@link Collator#getAvailableStyles} will return a list of styles that ilib
23532  * currently knows about for any given locale. If the value of the style option is 
23533  * not recognized for a locale, it will be ignored. Default style is "standard".<p>
23534  * 
23535  * <li><i>usage</i> - Whether this collator will be used for searching or sorting.
23536  * Valid values are simply the strings "sort" or "search". When used for sorting,
23537  * it is good idea if a collator produces a stable sort. That is, the order of the 
23538  * sorted array of strings should not depend on the order of the strings in the
23539  * input array. As such, when a collator is supposed to act case insensitively, 
23540  * it nonetheless still distinguishes between case after all other criteria
23541  * are satisfied so that strings that are distinguished only by case do not sort
23542  * randomly. For searching, we would like to match two strings that different only 
23543  * by case, so the collator must return equals in that situation instead of 
23544  * further distinguishing by case. Default is "sort".
23545  * 
23546  * <li><i>numeric</i> - Treat the left and right strings as if they started with
23547  * numbers and sort them numerically rather than lexically.
23548  * 
23549  * <li><i>ignorePunctuation</i> - Skip punctuation characters when comparing the
23550  * strings.
23551  *  
23552  * <li>onLoad - a callback function to call when the collator object is fully 
23553  * loaded. When the onLoad option is given, the collator object will attempt to
23554  * load any missing locale data using the ilib loader callback.
23555  * When the constructor is done (even if the data is already preassembled), the 
23556  * onLoad function is called with the current instance as a parameter, so this
23557  * callback can be used with preassembled or dynamic loading or a mix of the two.
23558  * 
23559  * <li>sync - tell whether to load any missing locale data synchronously or 
23560  * asynchronously. If this option is given as "false", then the "onLoad"
23561  * callback must be given, as the instance returned from this constructor will
23562  * not be usable for a while. 
23563  *
23564  * <li><i>loadParams</i> - an object containing parameters to pass to the 
23565  * loader callback function when locale data is missing. The parameters are not
23566  * interpretted or modified in any way. They are simply passed along. The object 
23567  * may contain any property/value pairs as long as the calling code is in
23568  * agreement with the loader callback function as to what those parameters mean.
23569  * 
23570  * <li><i>useNative</i> - when this option is true, use the native Intl object
23571  * provided by the Javascript engine, if it exists, to implement this class. If
23572  * it doesn't exist, or if this parameter is false, then this class uses a pure 
23573  * Javascript implementation, which is slower and uses a lot more memory, but 
23574  * works everywhere that ilib works. Default is "true".
23575  * </ul>
23576  * 
23577  * <h2>Operation</h2>
23578  * 
23579  * The Collator constructor returns a collator object tailored with the above 
23580  * options. The object contains an internal compare() method which compares two 
23581  * strings according to those options. This can be used directly to compare
23582  * two strings, but is not useful for passing to the javascript sort function
23583  * because then it will not have its collation data available. Instead, use the 
23584  * getComparator() method to retrieve a function that is bound to the collator
23585  * object. (You could also bind it yourself using ilib.bind()). The bound function 
23586  * can be used with the standard Javascript array sorting algorithm, or as a 
23587  * comparator with your own sorting algorithm.<p>
23588  * 
23589  * Example using the standard Javascript array sorting call with the bound
23590  * function:<p>
23591  * 
23592  * <code>
23593  * <pre>
23594  * var arr = ["ö", "oe", "ü", "o", "a", "ae", "u", "ß", "ä"];
23595  * var collator = new Collator({locale: 'de-DE', style: "dictionary"});
23596  * arr.sort(collator.getComparator());
23597  * console.log(JSON.stringify(arr));
23598  * </pre>
23599  * </code>
23600  * <p>
23601  * 
23602  * Would give the output:<p>
23603  * 
23604  * <code>
23605  * <pre>
23606  * ["a", "ae", "ä", "o", "oe", "ö", "ß", "u", "ü"]
23607  * </pre>
23608  * </code>
23609  * 
23610  * When sorting an array of Javascript objects according to one of the 
23611  * string properties of the objects, wrap the collator's compare function 
23612  * in your own comparator function that knows the structure of the objects
23613  * being sorted:<p>
23614  * 
23615  * <code>
23616  * <pre>
23617  * var collator = new Collator({locale: 'de-DE'});
23618  * var myComparator = function (collator) {
23619  *   var comparator = collator.getComparator();
23620  *   // left and right are your own objects
23621  *   return function (left, right) {
23622  *   	return comparator(left.x.y.textProperty, right.x.y.textProperty);
23623  *   };
23624  * };
23625  * arr.sort(myComparator(collator));
23626  * </pre>
23627  * </code>
23628  * <p>
23629  * 
23630  * <h2>Sort Keys</h2>
23631  * 
23632  * The collator class also has a method to retrieve the sort key for a
23633  * string. The sort key is an array of values that represent how each  
23634  * character in the string should be collated according to the characteristics
23635  * of the collation algorithm and the given options. Thus, sort keys can be 
23636  * compared directly value-for-value with other sort keys that were generated 
23637  * by the same collator, and the resulting ordering is guaranteed to be the 
23638  * same as if the original strings were compared by the collator.
23639  * Sort keys generated by different collators are not guaranteed to give
23640  * any reasonable results when compared together unless the two collators 
23641  * were constructed with 
23642  * exactly the same options and therefore end up representing the exact same 
23643  * collation sequence.<p>
23644  * 
23645  * A good rule of thumb is that you would use a sort key if you had 10 or more
23646  * items to sort or if your array might be resorted arbitrarily. For example, if your 
23647  * user interface was displaying a table with 100 rows in it, and each row had
23648  * 4 sortable text columns which could be sorted in acending or descending order,
23649  * the recommended practice would be to generate a sort key for each of the 4
23650  * sortable fields in each row and store that in the Javascript representation of the
23651  * table data. Then, when the user clicks on a column header to resort the
23652  * table according to that column, the resorting would be relatively quick 
23653  * because it would only be comparing arrays of values, and not recalculating 
23654  * the collation values for each character in each string for every comparison.<p>
23655  * 
23656  * For tables that are large, it is usually a better idea to do the sorting
23657  * on the server side, especially if the table is the result of a database
23658  * query. In this case, the table is usually a view of the cursor of a large
23659  * results set, and only a few entries are sent to the front end at a time.
23660  * In order to sort the set efficiently, it should be done on the database
23661  * level instead.
23662  * 
23663  * <h2>Data</h2>
23664  * 
23665  * Doing correct collation entails a huge amount of mapping data, much of which is
23666  * not necessary when collating in one language with one script, which is the most
23667  * common case. Thus, ilib implements a number of ways to include the data you
23668  * need or leave out the data you don't need using the JS assembly tool:
23669  * 
23670  * <ol>
23671  * <li>Full multilingual data - if you are sorting multilingual data and need to collate 
23672  * text written in multiple scripts, you can use the directive "!data collation/ducet" to 
23673  * load in the full collation data.  This allows the collator to perform the entire 
23674  * Unicode Collation Algorithm (UCA) based on the Default Unicode Collation Element 
23675  * Table (DUCET). The data is very large, on the order of multiple megabytes, but 
23676  * sometimes it is necessary.
23677  * <li>A few scripts - if you are sorting text written in only a few scripts, you may 
23678  * want to include only the data for those scripts. Each ISO 15924 script code has its
23679  * own data available in a separate file, so you can use the data directive to include
23680  * only the data for the scripts you need. For example, use  
23681  * "!data collation/Latn" to retrieve the collation information for the Latin script.
23682  * Because the "ducet" table mentioned in the previous point is a superset of the 
23683  * tables for all other scripts, you do not need to include explicitly the data for 
23684  * any particular script when using "ducet". That is, you either include "ducet" or 
23685  * you include a specific list of scripts.
23686  * <li>Only one script - if you are sorting text written only in one script, you can
23687  * either include the data directly as in the previous point, or you can rely on the 
23688  * locale to include the correct data for you. In this case, you can use the directive
23689  * "!data collate" to load in the locale's collation data for its most common script.
23690  * </ol>
23691  *   
23692  * With any of the above ways of including the data, the collator will only perform the
23693  * correct language-sensitive sorting for the given locale. All other scripts will be
23694  * sorted in the default manner according to the UCA. For example, if you include the
23695  * "ducet" data and pass in "de-DE" (German for Germany) as the locale spec, then
23696  * only the Latin script (the default script for German) will be sorted according to
23697  * German rules. All other scripts in the DUCET, such as Japanese or Arabic, will use 
23698  * the default UCA collation rules.<p>
23699  * 
23700  * If this collator encounters a character for which it has no collation data, it will
23701  * sort those characters by pure Unicode value after all characters for which it does have
23702  * collation data. For example, if you only loaded in the German collation data (ie. the
23703  * data for the Latin script tailored to German) to sort a list of person names, but that
23704  * list happens to include the names of a few Japanese people written in Japanese 
23705  * characters, the Japanese names will sort at the end of the list after all German names,
23706  * and will sort according to the Unicode values of the characters.
23707  * 
23708  * @constructor
23709  * @param {Object} options options governing how the resulting comparator 
23710  * function will operate
23711  */
23712 var Collator = function(options) {
23713 	var sync = true,
23714 		loadParams = undefined,
23715 		useNative = true;
23716 
23717 	// defaults
23718 	/** 
23719 	 * @private
23720 	 * @type {Locale} 
23721 	 */
23722 	this.locale = new Locale(ilib.getLocale());
23723 	
23724 	/** @private */
23725 	this.caseFirst = "upper";
23726 	/** @private */
23727 	this.sensitivity = "variant";
23728 	/** @private */
23729 	this.level = 4;
23730 	/** @private */
23731 	this.usage = "sort";
23732 	/** @private */
23733 	this.reverse = false;
23734 	/** @private */
23735 	this.numeric = false;
23736 	/** @private */
23737 	this.style = "default";
23738 	/** @private */
23739 	this.ignorePunctuation = false;
23740 	
23741 	if (options) {
23742 		if (options.locale) {
23743 			this.locale = (typeof(options.locale) === 'string') ? new Locale(options.locale) : options.locale;
23744 		}
23745 		if (options.sensitivity) {
23746 			switch (options.sensitivity) {
23747 				case 'primary':
23748 				case 'base':
23749 					this.sensitivity = "base";
23750 					this.level = 1;
23751 					break;
23752 				case 'secondary':
23753 				case 'accent':
23754 					this.sensitivity = "accent";
23755 					this.level = 2;
23756 					break;
23757 				case 'tertiary':
23758 				case 'case':
23759 					this.sensitivity = "case";
23760 					this.level = 3;
23761 					break;
23762 				case 'quaternary':
23763 				case 'variant':
23764 					this.sensitivity = "variant";
23765 					this.level = 4;
23766 					break;
23767 			}
23768 		}
23769 		if (typeof(options.upperFirst) !== 'undefined') {
23770 			this.caseFirst = options.upperFirst ? "upper" : "lower"; 
23771 		}
23772 		
23773 		if (typeof(options.ignorePunctuation) !== 'undefined') {
23774 			this.ignorePunctuation = options.ignorePunctuation;
23775 		}
23776 		if (typeof(options.sync) !== 'undefined') {
23777 			sync = (options.sync == true);
23778 		}
23779 		
23780 		loadParams = options.loadParams;
23781 		if (typeof(options.useNative) !== 'undefined') {
23782 			useNative = options.useNative;
23783 		}
23784 		
23785 		if (options.usage === "sort" || options.usage === "search") {
23786 			this.usage = options.usage;
23787 		}
23788 		
23789 		if (typeof(options.reverse) === 'boolean') {
23790 			this.reverse = options.reverse;
23791 		}
23792 
23793 		if (typeof(options.numeric) === 'boolean') {
23794 			this.numeric = options.numeric;
23795 		}
23796 		
23797 		if (typeof(options.style) === 'string') {
23798 			this.style = options.style;
23799 		}
23800 	}
23801 
23802 	if (this.usage === "sort") {
23803 		// produces a stable sort
23804 		this.level = 4;
23805 	}
23806 
23807 	if (useNative && typeof(Intl) !== 'undefined' && Intl) {
23808 		// this engine is modern and supports the new Intl object!
23809 		//console.log("implemented natively");
23810 		/** 
23811 		 * @private
23812 		 * @type {{compare:function(string,string)}} 
23813 		 */
23814 		this.collator = new Intl.Collator(this.locale.getSpec(), {
23815 			sensitivity: this.sensitivity,
23816 			caseFirst: this.caseFirst,
23817 			ignorePunctuation: this.ignorePunctuation,
23818 			numeric: this.numeric,
23819 			usage: this.usage
23820 		});
23821 		
23822 		if (options && typeof(options.onLoad) === 'function') {
23823 			options.onLoad(this);
23824 		}
23825 	} else {
23826 		//console.log("implemented in pure JS");
23827 		if (!Collator.cache) {
23828 			Collator.cache = {};
23829 		}
23830 
23831 		// else implement in pure Javascript
23832 		Utils.loadData({
23833 			object: Collator, 
23834 			locale: this.locale, 
23835 			name: "collation.json",
23836 			sync: sync,
23837 			loadParams: loadParams, 
23838 			callback: ilib.bind(this, function (collation) {
23839 				if (!collation) {
23840 					collation = ilib.data.collation;
23841 					var spec = this.locale.getSpec().replace(/-/g, '_');
23842 					Collator.cache[spec] = collation;
23843 				}
23844 				this._init(collation);
23845 				new LocaleInfo(this.locale, {
23846 					sync: sync,
23847 					loadParams: loadParams,
23848 					onLoad: ilib.bind(this, function(li) {
23849 						this.li = li;
23850 						if (this.ignorePunctuation) {
23851 			    			isPunct._init(sync, loadParams, ilib.bind(this, function() {
23852 								if (options && typeof(options.onLoad) === 'function') {
23853 									options.onLoad(this);
23854 								}
23855 			    			}));
23856 		    			} else {
23857 							if (options && typeof(options.onLoad) === 'function') {
23858 								options.onLoad(this);
23859 							}
23860 		    			}
23861 		    		})
23862 				});
23863 			})
23864 		});
23865 	}
23866 };
23867 
23868 Collator.prototype = {
23869 	/**
23870 	 * @private
23871 	 * Bit pack an array of values into a single number
23872 	 * @param {number|null|Array.<number>} arr array of values to bit pack
23873 	 * @param {number} offset offset for the start of this map
23874 	 */
23875 	_pack: function (arr, offset) {
23876 		var value = 0;
23877 		if (arr) {
23878 			if (typeof(arr) === 'number') {
23879 				arr = [ arr ];
23880 			}
23881 			for (var i = 0; i < this.level; i++) {
23882 				var thisLevel = (typeof(arr[i]) !== "undefined" ? arr[i] : 0);
23883 				if (i === 0) {
23884 					thisLevel += offset;
23885 				}
23886 				if (i > 0) {
23887 					value <<= this.collation.bits[i];	
23888 				}
23889 				if (i === 2 && this.caseFirst === "lower") {
23890 					// sort the lower case first instead of upper
23891 					value = value | (1 - thisLevel);
23892 				} else {
23893 					value = value | thisLevel;
23894 				}
23895 			}
23896 		}
23897 		return value;
23898 	},
23899 	
23900 	/**
23901 	 * @private
23902 	 * Return the rule packed into an array of collation elements.
23903 	 * @param {Array.<number|null|Array.<number>>} rule
23904 	 * @param {number} offset
23905 	 * @return {Array.<number>} a bit-packed array of numbers
23906 	 */
23907 	_packRule: function(rule, offset) {
23908 		if (ilib.isArray(rule[0])) {
23909 			var ret = [];
23910 			for (var i = 0; i < rule.length; i++) {
23911 				ret.push(this._pack(rule[i], offset));
23912 			}
23913 			return ret;
23914 		} else {
23915 			return [ this._pack(rule, offset) ];
23916 		}
23917 	},
23918     
23919 	/**
23920 	 * @private
23921 	 */
23922 	_addChars: function (str, offset) {
23923 		var gs = new GlyphString(str);
23924 		var it = gs.charIterator();
23925 		var c;
23926 		
23927 		while (it.hasNext()) {
23928 			c = it.next();
23929 			if (c === "'") {
23930 				// escape a sequence of chars as one collation element
23931 				c = "";
23932 				var x = "";
23933 				while (it.hasNext() && x !== "'") {
23934 					c += x;
23935 					x = it.next();
23936 				}
23937 			}
23938 			this.lastMap++;
23939 			this.map[c] = this._packRule([this.lastMap], offset);
23940 		}
23941 	},
23942 	
23943 	/**
23944 	 * @private
23945 	 */
23946 	_addRules: function(rules, start) {
23947 		var p;
23948     	for (var r in rules.map) {
23949     		if (r) {
23950     			this.map[r] = this._packRule(rules.map[r], start);
23951     			p = typeof(rules.map[r][0]) === 'number' ? rules.map[r][0] : rules.map[r][0][0]; 
23952     			this.lastMap = Math.max(p + start, this.lastMap);
23953     		}
23954     	}
23955     	
23956     	if (typeof(rules.ranges) !== 'undefined') {
23957     		// for each range, everything in the range goes in primary sequence from the start
23958     		for (var i = 0; i < rules.ranges.length; i++) {
23959     			var range = rules.ranges[i];
23960     			
23961     			this.lastMap = range.start;
23962     			if (typeof(range.chars) === "string") {
23963     				this._addChars(range.chars, start);
23964     			} else {
23965     				for (var k = 0; k < range.chars.length; k++) {
23966     					this._addChars(range.chars[k], start);
23967     				}
23968     			}
23969     		}
23970     	}
23971 	},
23972 	
23973 	/**
23974      * @private
23975      */
23976     _init: function(rules) {
23977     	var rule = this.style;
23978     	while (typeof(rule) === 'string') {
23979     		rule = rules[rule];
23980     	}
23981     	if (!rule) {
23982     		rule = "default";
23983         	while (typeof(rule) === 'string') {
23984         		rule = rules[rule];
23985         	}
23986     	}
23987     	if (!rule) {
23988     		this.map = {};
23989     		return;
23990     	}
23991     	
23992     	/** 
23993     	 * @private
23994     	 * @type {{scripts:Array.<string>,bits:Array.<number>,maxes:Array.<number>,bases:Array.<number>,map:Object.<string,Array.<number|null|Array.<number>>>}}
23995     	 */
23996     	this.collation = rule;
23997     	this.map = {};
23998     	this.lastMap = -1;
23999     	this.keysize = this.collation.keysize[this.level-1];
24000     	
24001     	if (typeof(this.collation.inherit) !== 'undefined') {
24002     		for (var i = 0; i < this.collation.inherit.length; i++) {
24003     			var col = this.collation.inherit[i];
24004     			rule = typeof(col) === 'object' ? col.name : col;
24005     			if (rules[rule]) {
24006     				this._addRules(rules[rule], col.start || this.lastMap+1);
24007     			}
24008     		}
24009     	}
24010     	this._addRules(this.collation, this.lastMap+1);
24011     },
24012     
24013     /**
24014      * @private
24015      */
24016     _basicCompare: function(left, right) {
24017 		var l = (left instanceof NormString) ? left : new NormString(left),
24018 			r = (right instanceof NormString) ? right : new NormString(right),
24019 			lchar, 
24020 			rchar,
24021 			lelements,
24022 			relements;
24023 		
24024 		if (this.numeric) {
24025 			var lvalue = new INumber(left, {locale: this.locale});
24026 			var rvalue = new INumber(right, {locale: this.locale});
24027 			if (!isNaN(lvalue.valueOf()) && !isNaN(rvalue.valueOf())) {
24028 				var diff = lvalue.valueOf() - rvalue.valueOf();
24029 				if (diff) {
24030 					return diff;
24031 				} else {
24032 					// skip the numeric part and compare the rest lexically
24033 					l = new NormString(left.substring(lvalue.parsed.length));
24034 					r = new NormString(right.substring(rvalue.parsed.length));
24035 				}
24036 			}
24037 			// else if they aren't both numbers, then let the code below take care of the lexical comparison instead
24038 		}
24039 			
24040 		lelements = new ElementIterator(new CodePointSource(l, this.ignorePunctuation), this.map, this.keysize);
24041 		relements = new ElementIterator(new CodePointSource(r, this.ignorePunctuation), this.map, this.keysize);
24042 		
24043 		while (lelements.hasNext() && relements.hasNext()) {
24044 			var diff = lelements.next() - relements.next();
24045 			if (diff) {
24046 				return diff;
24047 			}
24048 		}
24049 		if (!lelements.hasNext() && !relements.hasNext()) {
24050 			return 0;
24051 		} else if (lelements.hasNext()) {
24052 			return 1;
24053 		} else {
24054 			return -1;
24055 		}
24056     },
24057     
24058 	/**
24059 	 * Compare two strings together according to the rules of this 
24060 	 * collator instance. Do not use this function directly with 
24061 	 * Array.sort, as it will not have its collation data available
24062 	 * and therefore will not function properly. Use the function
24063 	 * returned by getComparator() instead.
24064 	 * 
24065 	 * @param {string} left the left string to compare
24066 	 * @param {string} right the right string to compare
24067 	 * @return {number} a negative number if left comes before right, a
24068 	 * positive number if right comes before left, and zero if left and 
24069 	 * right are equivalent according to this collator
24070 	 */
24071 	compare: function (left, right) {
24072 		// last resort: use the "C" locale
24073 		if (this.collator) {
24074 			// implemented by the core engine
24075 			return this.collator.compare(left, right);
24076 		}
24077 
24078 		var ret = this._basicCompare(left, right);
24079 		return this.reverse ? -ret : ret;
24080 	},
24081 	
24082 	/**
24083 	 * Return a comparator function that can compare two strings together
24084 	 * according to the rules of this collator instance. The function 
24085 	 * returns a negative number if the left 
24086 	 * string comes before right, a positive number if the right string comes 
24087 	 * before the left, and zero if left and right are equivalent. If the
24088 	 * reverse property was given as true to the collator constructor, this 
24089 	 * function will
24090 	 * switch the sign of those values to cause sorting to happen in the
24091 	 * reverse order.
24092 	 * 
24093 	 * @return {function(...)|undefined} a comparator function that 
24094 	 * can compare two strings together according to the rules of this 
24095 	 * collator instance
24096 	 */
24097 	getComparator: function() {
24098 		// bind the function to this instance so that we have the collation
24099 		// rules available to do the work
24100 		if (this.collator) {
24101 			// implemented by the core engine
24102 			return this.collator.compare;
24103 		}
24104 		
24105 		return ilib.bind(this, this.compare);
24106 	},
24107 	
24108 	/**
24109 	 * Return a sort key string for the given string. The sort key
24110 	 * string is a list of values that represent each character 
24111 	 * in the original string. The sort key
24112 	 * values for any particular character consists of 3 numbers that
24113 	 * encode the primary, secondary, and tertiary characteristics
24114 	 * of that character. The values of each characteristic are 
24115 	 * modified according to the strength of this collator instance 
24116 	 * to give the correct collation order. The idea is that this
24117 	 * sort key string is directly comparable byte-for-byte to 
24118 	 * other sort key strings generated by this collator without
24119 	 * any further knowledge of the collation rules for the locale.
24120 	 * More formally, if a < b according to the rules of this collation, 
24121 	 * then it is guaranteed that sortkey(a) < sortkey(b) when compared
24122 	 * byte-for-byte. The sort key string can therefore be used
24123 	 * without the collator to sort an array of strings efficiently
24124 	 * because the work of determining the applicability of various
24125 	 * collation rules is done once up-front when generating 
24126 	 * the sort key.<p>
24127 	 * 
24128 	 * The sort key string can be treated as a regular, albeit somewhat
24129 	 * odd-looking, string. That is, it can be pass to regular 
24130 	 * Javascript functions without problems.  
24131 	 * 
24132 	 * @param {string} str the original string to generate the sort key for
24133 	 * @return {string} a sort key string for the given string
24134 	 */
24135 	sortKey: function (str) {
24136 		if (!str) {
24137 			return "";
24138 		}
24139 		
24140 		if (this.collator) {
24141 			// native, no sort keys available
24142 			return str;
24143 		}
24144 		
24145 		if (this.numeric) {
24146 			var v = new INumber(str, {locale: this.locale});
24147 			var s = isNaN(v.valueOf()) ? "" : v.valueOf().toString(16);
24148 			return JSUtils.pad(s, 16);	
24149 		} else {
24150 			var n = (typeof(str) === "string") ? new NormString(str) : str,
24151 				ret = "",
24152 				lelements = new ElementIterator(new CodePointSource(n, this.ignorePunctuation), this.map, this.keysize),
24153 				element;
24154 			
24155 			while (lelements.hasNext()) {
24156 				element = lelements.next();
24157 				if (this.reverse) {
24158 					// for reverse, take the bitwise inverse
24159 					element = (1 << this.keysize) - element;
24160 				}
24161 				ret += JSUtils.pad(element.toString(16), this.keysize/4);	
24162 			}
24163 		}
24164 		return ret;
24165 	}
24166 };
24167 
24168 /**
24169  * Retrieve the list of collation style names that are available for the 
24170  * given locale. This list varies depending on the locale, and depending
24171  * on whether or not the data for that locale was assembled into this copy
24172  * of ilib.
24173  * 
24174  * @param {Locale|string=} locale The locale for which the available
24175  * styles are being sought
24176  * @return Array.<string> an array of style names that are available for
24177  * the given locale
24178  */
24179 Collator.getAvailableStyles = function (locale) {
24180 	return [ "standard" ];
24181 };
24182 
24183 /**
24184  * Retrieve the list of ISO 15924 script codes that are available in this
24185  * copy of ilib. This list varies depending on whether or not the data for 
24186  * various scripts was assembled into this copy of ilib. If the "ducet"
24187  * data is assembled into this copy of ilib, this method will report the
24188  * entire list of scripts as being available. If a collator instance is
24189  * instantiated with a script code that is not on the list returned by this
24190  * function, it will be ignored and text in that script will be sorted by
24191  * numeric Unicode values of the characters.
24192  * 
24193  * @return Array.<string> an array of ISO 15924 script codes that are 
24194  * available
24195  */
24196 Collator.getAvailableScripts = function () {
24197 	return [ "Latn" ];
24198 };
24199 
24200 
24201 
24202 /*< nfd/all.js */
24203 /*
24204  * all.js - include file for normalization data for a particular script
24205  * 
24206  * Copyright © 2013-2015, JEDLSoft
24207  *
24208  * Licensed under the Apache License, Version 2.0 (the "License");
24209  * you may not use this file except in compliance with the License.
24210  * You may obtain a copy of the License at
24211  *
24212  *     http://www.apache.org/licenses/LICENSE-2.0
24213  *
24214  * Unless required by applicable law or agreed to in writing, software
24215  * distributed under the License is distributed on an "AS IS" BASIS,
24216  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24217  *
24218  * See the License for the specific language governing permissions and
24219  * limitations under the License.
24220  */
24221 /* WARNING: THIS IS A FILE GENERATED BY gennorm.js. DO NOT EDIT BY HAND. */
24222 // !data normdata nfd/all
24223 ilib.extend(ilib.data.norm, ilib.data.normdata);
24224 ilib.extend(ilib.data.norm.nfd, ilib.data.nfd_all);
24225 ilib.data.normdata = undefined;
24226 ilib.data.nfd_all = undefined;
24227 /*< nfkd/all.js */
24228 /*
24229  * all.js - include file for normalization data for a particular script
24230  * 
24231  * Copyright © 2013-2015, JEDLSoft
24232  *
24233  * Licensed under the Apache License, Version 2.0 (the "License");
24234  * you may not use this file except in compliance with the License.
24235  * You may obtain a copy of the License at
24236  *
24237  *     http://www.apache.org/licenses/LICENSE-2.0
24238  *
24239  * Unless required by applicable law or agreed to in writing, software
24240  * distributed under the License is distributed on an "AS IS" BASIS,
24241  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24242  *
24243  * See the License for the specific language governing permissions and
24244  * limitations under the License.
24245  */
24246 /* WARNING: THIS IS A FILE GENERATED BY gennorm.js. DO NOT EDIT BY HAND. */
24247 // !depends nfd/all.js
24248 // !data normdata nfkd/all
24249 ilib.extend(ilib.data.norm, ilib.data.normdata);
24250 ilib.extend(ilib.data.norm.nfkd, ilib.data.nfkd_all);
24251 ilib.data.normdata = undefined;
24252 ilib.data.nfkd_all = undefined;
24253 /*< nfkc/all.js */
24254 /*
24255  * all.js - include file for normalization data for a particular script
24256  * 
24257  * Copyright © 2013-2015, JEDLSoft
24258  *
24259  * Licensed under the Apache License, Version 2.0 (the "License");
24260  * you may not use this file except in compliance with the License.
24261  * You may obtain a copy of the License at
24262  *
24263  *     http://www.apache.org/licenses/LICENSE-2.0
24264  *
24265  * Unless required by applicable law or agreed to in writing, software
24266  * distributed under the License is distributed on an "AS IS" BASIS,
24267  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24268  *
24269  * See the License for the specific language governing permissions and
24270  * limitations under the License.
24271  */
24272 /* WARNING: THIS IS A FILE GENERATED BY gennorm.js. DO NOT EDIT BY HAND. */
24273 // !depends nfd/all.js nfkd/all.js
24274 // !data norm
24275 ilib.extend(ilib.data.norm, ilib.data.normdata);
24276 ilib.data.normdata = undefined;
24277 
24278 /*< LocaleMatcher.js */
24279 /*
24280  * LocaleMatcher.js - Locale matcher definition
24281  * 
24282  * Copyright © 2013-2015, JEDLSoft
24283  *
24284  * Licensed under the Apache License, Version 2.0 (the "License");
24285  * you may not use this file except in compliance with the License.
24286  * You may obtain a copy of the License at
24287  *
24288  *     http://www.apache.org/licenses/LICENSE-2.0
24289  *
24290  * Unless required by applicable law or agreed to in writing, software
24291  * distributed under the License is distributed on an "AS IS" BASIS,
24292  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24293  *
24294  * See the License for the specific language governing permissions and
24295  * limitations under the License.
24296  */
24297 
24298 // !depends ilib.js Locale.js Utils.js
24299 // !data likelylocales
24300 
24301 
24302 /**
24303  * @class
24304  * Create a new locale matcher instance. This is used
24305  * to see which locales can be matched with each other in
24306  * various ways.<p>
24307  * 
24308  * The options object may contain any of the following properties:
24309  * 
24310  * <ul>
24311  * <li><i>locale</i> - the locale to match
24312  * 
24313  * <li><i>onLoad</i> - a callback function to call when the locale matcher object is fully 
24314  * loaded. When the onLoad option is given, the locale matcher object will attempt to
24315  * load any missing locale data using the ilib loader callback.
24316  * When the constructor is done (even if the data is already preassembled), the 
24317  * onLoad function is called with the current instance as a parameter, so this
24318  * callback can be used with preassembled or dynamic loading or a mix of the two.
24319  * 
24320  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
24321  * asynchronously. If this option is given as "false", then the "onLoad"
24322  * callback must be given, as the instance returned from this constructor will
24323  * not be usable for a while. 
24324  *
24325  * <li><i>loadParams</i> - an object containing parameters to pass to the 
24326  * loader callback function when locale data is missing. The parameters are not
24327  * interpretted or modified in any way. They are simply passed along. The object 
24328  * may contain any property/value pairs as long as the calling code is in
24329  * agreement with the loader callback function as to what those parameters mean.
24330  * </ul>
24331  * 
24332  * 
24333  * @constructor
24334  * @param {Object} options parameters to initialize this matcher 
24335  */
24336 var LocaleMatcher = function(options) {
24337 	var sync = true,
24338 	    loadParams = undefined;
24339 	
24340 	this.locale = new Locale();
24341 	
24342 	if (options) {
24343 		if (typeof(options.locale) !== 'undefined') {
24344 			this.locale = (typeof(options.locale) === 'string') ? new Locale(options.locale) : options.locale;
24345 		}
24346 		
24347 		if (typeof(options.sync) !== 'undefined') {
24348 			sync = (options.sync == true);
24349 		}
24350 		
24351 		if (typeof(options.loadParams) !== 'undefined') {
24352 			loadParams = options.loadParams;
24353 		}
24354 	}
24355 
24356 	if (!LocaleMatcher.cache) {
24357 		LocaleMatcher.cache = {};
24358 	}
24359 
24360 	if (typeof(ilib.data.likelylocales) === 'undefined') {
24361 		Utils.loadData({
24362 			object: LocaleMatcher, 
24363 			locale: "-", 
24364 			name: "likelylocales.json", 
24365 			sync: sync, 
24366 			loadParams: loadParams, 
24367 			callback: ilib.bind(this, function (info) {
24368 				if (!info) {
24369 					info = {};
24370 					var spec = this.locale.getSpec().replace(/-/g, "_");
24371 					LocaleMatcher.cache[spec] = info;
24372 				}
24373 				/** @type {Object.<string,string>} */
24374 				this.info = info;
24375 				if (options && typeof(options.onLoad) === 'function') {
24376 					options.onLoad(this);
24377 				}
24378 			})
24379 		});
24380 	} else {
24381 		this.info = ilib.data.likelylocales;
24382 	}
24383 };
24384 
24385 
24386 LocaleMatcher.prototype = {
24387 	/**
24388 	 * Return the locale used to construct this instance. 
24389 	 * @return {Locale|undefined} the locale for this matcher
24390 	 */
24391 	getLocale: function() {
24392 		return this.locale;
24393 	},
24394 	
24395 	/**
24396 	 * Return an Locale instance that is fully specified based on partial information
24397 	 * given to the constructor of this locale matcher instance. For example, if the locale
24398 	 * spec given to this locale matcher instance is simply "ru" (for the Russian language), 
24399 	 * then it will fill in the missing region and script tags and return a locale with 
24400 	 * the specifier "ru-Cyrl-RU". (ie. Russian language, Cyrillic, Russian Federation).
24401 	 * Any one or two of the language, script, or region parts may be left unspecified,
24402 	 * and the other one or two parts will be filled in automatically. If this
24403 	 * class has no information about the given locale, then the locale of this
24404 	 * locale matcher instance is returned unchanged.
24405 	 * 
24406 	 * @returns {Locale} the most likely completion of the partial locale given
24407 	 * to the constructor of this locale matcher instance
24408 	 */
24409 	getLikelyLocale: function () {
24410 		if (typeof(this.info[this.locale.getSpec()]) === 'undefined') {
24411 			return this.locale;
24412 		}
24413 		
24414 		return new Locale(this.info[this.locale.getSpec()]);
24415 	}
24416 };
24417 
24418 
24419 /*< CaseMapper.js */
24420 /*
24421  * caseMapper.js - define upper- and lower-case mapper
24422  * 
24423  * Copyright © 2014-2015, JEDLSoft
24424  *
24425  * Licensed under the Apache License, Version 2.0 (the "License");
24426  * you may not use this file except in compliance with the License.
24427  * You may obtain a copy of the License at
24428  *
24429  *     http://www.apache.org/licenses/LICENSE-2.0
24430  *
24431  * Unless required by applicable law or agreed to in writing, software
24432  * distributed under the License is distributed on an "AS IS" BASIS,
24433  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24434  *
24435  * See the License for the specific language governing permissions and
24436  * limitations under the License.
24437  */
24438 
24439 // !depends Locale.js IString.js
24440 
24441 
24442 
24443 /**
24444  * @class
24445  * Create a new string mapper instance that maps strings to upper or
24446  * lower case. This mapping will work for any string as characters 
24447  * that have no case will be returned unchanged.<p>
24448  * 
24449  * The options may contain any of the following properties:
24450  * 
24451  * <ul>
24452  * <li><i>locale</i> - locale to use when loading the mapper. Some maps are 
24453  * locale-dependent, and this locale selects the right one. Default if this is
24454  * not specified is the current locale.
24455  * 
24456  * <li><i>direction</i> - "toupper" for upper-casing, or "tolower" for lower-casing.
24457  * Default if not specified is "toupper".
24458  * </ul>
24459  * 
24460  * 
24461  * @constructor
24462  * @param {Object=} options options to initialize this mapper 
24463  */
24464 var CaseMapper = function (options) {
24465 	this.up = true;
24466 	this.locale = new Locale();
24467 	
24468 	if (options) {
24469 		if (typeof(options.locale) !== 'undefined') {
24470 			this.locale = (typeof(options.locale) === 'string') ? new Locale(options.locale) : options.locale;
24471 		}
24472 		
24473 		this.up = (!options.direction || options.direction === "toupper");
24474 	}
24475 
24476 	this.mapData = this.up ? {
24477 		"ß": "SS",		// German
24478 		'ΐ': 'Ι',		// Greek
24479 		'ά': 'Α',
24480 		'έ': 'Ε',
24481 		'ή': 'Η',
24482 		'ί': 'Ι',
24483 		'ΰ': 'Υ',
24484 		'ϊ': 'Ι',
24485 		'ϋ': 'Υ',
24486 		'ό': 'Ο',
24487 		'ύ': 'Υ',
24488 		'ώ': 'Ω',
24489 		'Ӏ': 'Ӏ',		// Russian and slavic languages
24490 		'ӏ': 'Ӏ'
24491 	} : {
24492 		'Ӏ': 'Ӏ'		// Russian and slavic languages
24493 	};
24494 
24495 	switch (this.locale.getLanguage()) {
24496 		case "az":
24497 		case "tr":
24498 		case "crh":
24499 		case "kk":
24500 		case "krc":
24501 		case "tt":
24502 			var lower = "iı";
24503 			var upper = "İI";
24504 			this._setUpMap(lower, upper);
24505 			break;
24506 		case "fr":
24507 			if (this.up && this.locale.getRegion() !== "CA") {
24508 				this._setUpMap("àáâãäçèéêëìíîïñòóôöùúûü", "AAAAACEEEEIIIINOOOOUUUU");
24509 			}
24510 			break;
24511 	}
24512 	
24513 	if (ilib._getBrowser() === "ie") {
24514 		// IE is missing these mappings for some reason
24515 		if (this.up) {
24516 			this.mapData['ς'] = 'Σ';
24517 		}
24518 		this._setUpMap("ⲁⲃⲅⲇⲉⲋⲍⲏⲑⲓⲕⲗⲙⲛⲝⲟⲡⲣⲥⲧⲩⲫⲭⲯⲱⳁⳉⳋ", "ⲀⲂⲄⲆⲈⲊⲌⲎⲐⲒⲔⲖⲘⲚⲜⲞⲠⲢⲤⲦⲨⲪⲬⲮⲰⳀⳈⳊ"); // Coptic
24519 		// Georgian Nuskhuri <-> Asomtavruli
24520 		this._setUpMap("ⴀⴁⴂⴃⴄⴅⴆⴇⴈⴉⴊⴋⴌⴍⴎⴏⴐⴑⴒⴓⴔⴕⴖⴗⴘⴙⴚⴛⴜⴝⴞⴟⴠⴡⴢⴣⴤⴥ", "ႠႡႢႣႤႥႦႧႨႩႪႫႬႭႮႯႰႱႲႳႴႵႶႷႸႹႺႻႼႽႾႿჀჁჂჃჄჅ");	
24521 	}
24522 };
24523 
24524 CaseMapper.prototype = {
24525 	/** 
24526 	 * @private 
24527 	 */
24528 	_charMapper: function(string) {
24529 		if (!string) {
24530 			return string;
24531 		}
24532 		var input = (typeof(string) === 'string') ? new IString(string) : string.toString();
24533 		var ret = "";
24534 		var it = input.charIterator();
24535 		var c;
24536 		
24537 		while (it.hasNext()) {
24538 			c = it.next();
24539 			if (!this.up && c === 'Σ') {
24540 				if (it.hasNext()) {
24541 					c = it.next();
24542 					var code = c.charCodeAt(0);
24543 					// if the next char is not a greek letter, this is the end of the word so use the
24544 					// final form of sigma. Otherwise, use the mid-word form.
24545 					ret += ((code < 0x0388 && code !== 0x0386) || code > 0x03CE) ? 'ς' : 'σ';
24546 					ret += c.toLowerCase();
24547 				} else {
24548 					// no next char means this is the end of the word, so use the final form of sigma
24549 					ret += 'ς';
24550 				}
24551 			} else {
24552 				if (this.mapData[c]) {
24553 					ret += this.mapData[c];
24554 				} else {
24555 					ret += this.up ? c.toUpperCase() : c.toLowerCase();
24556 				}
24557 			}
24558 		}
24559 		
24560 		return ret;
24561 	},
24562 
24563 	/** @private */
24564 	_setUpMap: function(lower, upper) {
24565 		var from, to;
24566 		if (this.up) {
24567 			from = lower;
24568 			to = upper;
24569 		} else {
24570 			from = upper;
24571 			to = lower;
24572 		}
24573 		for (var i = 0; i < upper.length; i++) {
24574 			this.mapData[from[i]] = to[i];
24575 		}
24576 	},
24577 
24578 	/**
24579 	 * Return the locale that this mapper was constructed with. 
24580 	 * @returns {Locale} the locale that this mapper was constructed with
24581 	 */
24582 	getLocale: function () {
24583 		return this.locale;
24584 	},
24585 		
24586 	/**
24587 	 * Map a string to lower case in a locale-sensitive manner.
24588 	 * 
24589 	 * @param {string|undefined} string
24590 	 * @return {string|undefined}
24591 	 */
24592 	map: function (string) {
24593 		return this._charMapper(string);
24594 	}
24595 };
24596 
24597 
24598 /*< NumberingPlan.js */
24599 /*
24600  * NumPlan.js - Represent a phone numbering plan.
24601  * 
24602  * Copyright © 2014-2015, JEDLSoft
24603  *
24604  * Licensed under the Apache License, Version 2.0 (the "License");
24605  * you may not use this file except in compliance with the License.
24606  * You may obtain a copy of the License at
24607  *
24608  *     http://www.apache.org/licenses/LICENSE-2.0
24609  *
24610  * Unless required by applicable law or agreed to in writing, software
24611  * distributed under the License is distributed on an "AS IS" BASIS,
24612  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24613  *
24614  * See the License for the specific language governing permissions and
24615  * limitations under the License.
24616  */
24617 
24618 /*
24619 !depends 
24620 ilib.js 
24621 Locale.js 
24622 Utils.js
24623 JSUtils.js
24624 */
24625 
24626 // !data numplan
24627 
24628 
24629 /**
24630  * @class
24631  * Create a numbering plan information instance for a particular country's plan.<p>
24632  * 
24633  * The options may contain any of the following properties:
24634  * 
24635  * <ul>
24636  * <li><i>locale</i> - locale for which the numbering plan is sought. This locale
24637  * will be mapped to the actual numbering plan, which may be shared amongst a
24638  * number of countries.
24639  *
24640  * <li>onLoad - a callback function to call when the date format object is fully 
24641  * loaded. When the onLoad option is given, the DateFmt object will attempt to
24642  * load any missing locale data using the ilib loader callback.
24643  * When the constructor is done (even if the data is already preassembled), the 
24644  * onLoad function is called with the current instance as a parameter, so this
24645  * callback can be used with preassembled or dynamic loading or a mix of the two.
24646  * 
24647  * <li>sync - tell whether to load any missing locale data synchronously or 
24648  * asynchronously. If this option is given as "false", then the "onLoad"
24649  * callback must be given, as the instance returned from this constructor will
24650  * not be usable for a while.
24651  *  
24652  * <li><i>loadParams</i> - an object containing parameters to pass to the 
24653  * loader callback function when locale data is missing. The parameters are not
24654  * interpretted or modified in any way. They are simply passed along. The object 
24655  * may contain any property/value pairs as long as the calling code is in
24656  * agreement with the loader callback function as to what those parameters mean.
24657  * </ul>
24658  * 
24659  * @private
24660  * @constructor
24661  * @param {Object} options options governing the way this plan is loaded
24662  */
24663 var NumberingPlan = function (options) {
24664 	var sync = true,
24665 	    loadParams = {};
24666 	
24667 	this.locale = new Locale();
24668 
24669 	if (options) {
24670 		if (options.locale) {
24671 			this.locale = (typeof(options.locale) === 'string') ? new Locale(options.locale) : options.locale;
24672 		}
24673 		
24674 		if (typeof(options.sync) !== 'undefined') {
24675 			sync = (options.sync == true);
24676 		}
24677 		
24678 		if (options.loadParams) {
24679 			loadParams = options.loadParams;
24680 		}
24681 	}	
24682 
24683 	Utils.loadData({
24684 		name: "numplan.json",
24685 		object: NumberingPlan,
24686 		locale: this.locale,
24687 		sync: sync, 
24688 		loadParams: loadParams, 
24689 		callback: ilib.bind(this, function (npdata) {
24690 			if (!npdata) {
24691 				npdata = {
24692 					"region": "XX",
24693 					"skipTrunk": false,
24694 					"trunkCode": "0",
24695 					"iddCode": "00",
24696 					"dialingPlan": "closed",
24697 					"commonFormatChars": " ()-./",
24698 					"fieldLengths": {
24699 						"areaCode": 0,
24700 						"cic": 0,
24701 						"mobilePrefix": 0,
24702 						"serviceCode": 0
24703 					}
24704 				};
24705 			}
24706 
24707 			/** 
24708 			 * @type {{
24709 			 *   region:string,
24710 			 *   skipTrunk:boolean,
24711 			 *   trunkCode:string,
24712 			 *   iddCode:string,
24713 			 *   dialingPlan:string,
24714 			 *   commonFormatChars:string,
24715 			 *   fieldLengths:Object.<string,number>,
24716 			 *   contextFree:boolean,
24717 			 *   findExtensions:boolean,
24718 			 *   trunkRequired:boolean,
24719 			 *   extendedAreaCodes:boolean
24720 			 * }}
24721 			 */
24722 			this.npdata = npdata;
24723 			if (options && typeof(options.onLoad) === 'function') {
24724 				options.onLoad(this);
24725 			}
24726 		})
24727 	});
24728 };
24729 
24730 NumberingPlan.prototype = {
24731 	/**
24732 	 * Return the name of this plan. This may be different than the 
24733 	 * name of the region because sometimes multiple countries share 
24734 	 * the same plan.
24735 	 * @return {string} the name of the plan
24736 	 */
24737 	getName: function() {
24738 		return this.npdata.region;
24739 	},
24740 
24741 	/**
24742 	 * Return the trunk code of the current plan as a string.
24743 	 * @return {string|undefined} the trunk code of the plan or
24744 	 * undefined if there is no trunk code in this plan
24745 	 */
24746 	getTrunkCode: function() {
24747 		return this.npdata.trunkCode;
24748 	},
24749 	
24750 	/**
24751 	 * Return the international direct dialing code of this plan.
24752 	 * @return {string} the IDD code of this plan
24753 	 */
24754 	getIDDCode: function() {
24755 		return this.npdata.iddCode;	
24756 	},
24757 	
24758 	/**
24759 	 * Return the plan style for this plan. The plan style may be
24760 	 * one of:
24761 	 * 
24762 	 * <ul>
24763 	 * <li>"open" - area codes may be left off if the caller is 
24764 	 * dialing to another number within the same area code
24765 	 * <li>"closed" - the area code must always be specified, even
24766 	 * if calling another number within the same area code
24767 	 * </ul>
24768 	 * 
24769 	 * @return {string} the plan style, "open" or "closed"
24770 	 */
24771 	getPlanStyle: function() {	
24772 		return this.npdata.dialingPlan;
24773 	},
24774 	/** [Need Comment]
24775 	 * Return a contextFree
24776 	 *
24777 	 * @return {boolean}
24778 	 */
24779 	getContextFree: function() {
24780 		return this.npdata.contextFree;
24781 	},
24782 	/** [Need Comment]
24783 	 * Return a findExtensions
24784 	 * 
24785 	 * @return {boolean}
24786 	 */
24787 	getFindExtensions: function() {
24788 		return this.npdata.findExtensions;
24789 	},
24790 	/** [Need Comment]
24791 	 * Return a skipTrunk
24792 	 * 
24793 	 * @return {boolean}
24794 	 */
24795 	getSkipTrunk: function() {
24796 		return this.npdata.skipTrunk;
24797 	},
24798 	/** [Need Comment]
24799 	 * Return a skipTrunk
24800 	 * 
24801 	 * @return {boolean}
24802 	 */
24803 	getTrunkRequired: function() {
24804 		return this.npdata.trunkRequired;
24805 	},
24806 	/**
24807 	 * Return true if this plan uses extended area codes.
24808 	 * @return {boolean} true if the plan uses extended area codes
24809 	 */
24810 	getExtendedAreaCode: function() {
24811 		return this.npdata.extendedAreaCodes;
24812 	},
24813 	/**
24814 	 * Return a string containing all of the common format characters
24815 	 * used to format numbers.
24816 	 * @return {string} the common format characters fused in this locale
24817 	 */
24818 	getCommonFormatChars: function() {
24819 		return this.npdata.commonFormatChars;
24820 	},
24821 	
24822 	/**
24823 	 * Return the length of the field with the given name. If the length
24824 	 * is returned as 0, this means it is variable length.
24825 	 * 
24826 	 * @param {string} field name of the field for which the length is 
24827 	 * being sought
24828 	 * @return {number} if positive, this gives the length of the given 
24829 	 * field. If zero, the field is variable length. If negative, the
24830 	 * field is not known.
24831 	 */
24832 	getFieldLength: function (field) {
24833 		var dataField = this.npdata.fieldLengths;
24834 		
24835 		return dataField[field];
24836 	}
24837 };
24838 
24839 
24840 /*< PhoneLocale.js */
24841 /*
24842  * phoneloc.js - Represent a phone locale object.
24843  * 
24844  * Copyright © 2014-2015, JEDLSoft
24845  *
24846  * Licensed under the Apache License, Version 2.0 (the "License");
24847  * you may not use this file except in compliance with the License.
24848  * You may obtain a copy of the License at
24849  *
24850  *     http://www.apache.org/licenses/LICENSE-2.0
24851  *
24852  * Unless required by applicable law or agreed to in writing, software
24853  * distributed under the License is distributed on an "AS IS" BASIS,
24854  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24855  *
24856  * See the License for the specific language governing permissions and
24857  * limitations under the License.
24858  */
24859 
24860 /*
24861 !depends 
24862 ilib.js 
24863 Locale.js
24864 Utils.js
24865 */
24866 
24867 // !data phoneloc
24868 
24869 
24870 /**
24871  * @class
24872  * Extension of the locale class that has extra methods to map various numbers
24873  * related to phone number parsing.
24874  *
24875  * @param {Object} options Options that govern how this phone locale works
24876  * 
24877  * @private
24878  * @constructor
24879  * @extends Locale
24880  */
24881 var PhoneLocale = function(options) {
24882 	var region,
24883 		mcc,
24884 		cc,
24885 		sync = true,
24886 		loadParams = {},
24887 		locale;
24888 	
24889 	locale = (options && options.locale) || ilib.getLocale();
24890 
24891 	this.parent.call(this, locale);
24892 	
24893 	region = this.region;
24894 	
24895 	if (options) {
24896 		if (typeof(options.mcc) !== 'undefined') {
24897 			mcc = options.mcc;
24898 		}
24899 		
24900 		if (typeof(options.countryCode) !== 'undefined') {
24901 			cc = options.countryCode;
24902 		}
24903 
24904 		if (typeof(options.sync) !== 'undefined') {
24905 			sync = (options.sync == true);
24906 		}
24907 		
24908 		if (options.loadParams) {
24909 			loadParams = options.loadParams;
24910 		}
24911 	}
24912 
24913 	Utils.loadData({
24914 		name: "phoneloc.json",
24915 		object: PhoneLocale,
24916 		nonlocale: true,
24917 		sync: sync, 
24918 		loadParams: loadParams, 
24919 		callback: ilib.bind(this, function (data) {
24920 			/** @type {{mcc2reg:Object.<string,string>,cc2reg:Object.<string,string>,reg2cc:Object.<string,string>,area2reg:Object.<string,string>}} */
24921 			this.mappings = data;
24922 			
24923 			if (typeof(mcc) !== 'undefined') {
24924 				region = this.mappings.mcc2reg[mcc];	
24925 			}
24926 
24927 			if (typeof(cc) !== 'undefined') {
24928 				region = this.mappings.cc2reg[cc];
24929 			}
24930 
24931 			if (!region) {
24932 				region = "XX";
24933 			}
24934 
24935 			this.region = this._normPhoneReg(region);
24936 			this._genSpec();
24937 
24938 			if (options && typeof(options.onLoad) === 'function') {
24939 				options.onLoad(this);
24940 			}									
24941 		})
24942 	});
24943 };
24944 
24945 PhoneLocale.prototype = new Locale();
24946 PhoneLocale.prototype.parent = Locale;
24947 PhoneLocale.prototype.constructor = PhoneLocale;
24948 
24949 /**
24950  * Map a mobile carrier code to a region code.
24951  *
24952  * @static
24953  * @package
24954  * @param {string|undefined} mcc the MCC to map
24955  * @return {string|undefined} the region code
24956  */
24957 
24958 PhoneLocale.prototype._mapMCCtoRegion = function(mcc) {
24959 	if (!mcc) {
24960 		return undefined;
24961 	}
24962 	return this.mappings.mcc2reg && this.mappings.mcc2reg[mcc] || "XX";
24963 };
24964 
24965 /**
24966  * Map a country code to a region code.
24967  *
24968  * @static
24969  * @package
24970  * @param {string|undefined} cc the country code to map
24971  * @return {string|undefined} the region code
24972  */
24973 PhoneLocale.prototype._mapCCtoRegion = function(cc) {
24974 	if (!cc) {
24975 		return undefined;
24976 	}
24977 	return this.mappings.cc2reg && this.mappings.cc2reg[cc] || "XX";
24978 };
24979 
24980 /**
24981  * Map a region code to a country code.
24982  *
24983  * @static
24984  * @package
24985  * @param {string|undefined} region the region code to map
24986  * @return {string|undefined} the country code
24987  */
24988 PhoneLocale.prototype._mapRegiontoCC = function(region) {
24989 	if (!region) {
24990 		return undefined;
24991 	}
24992 	return this.mappings.reg2cc && this.mappings.reg2cc[region] || "0";
24993 };
24994 
24995 /**
24996  * Map a country code to a region code.
24997  *
24998  * @static
24999  * @package
25000  * @param {string|undefined} cc the country code to map
25001  * @param {string|undefined} area the area code within the country code's numbering plan
25002  * @return {string|undefined} the region code
25003  */
25004 PhoneLocale.prototype._mapAreatoRegion = function(cc, area) {
25005 	if (!cc) {
25006 		return undefined;
25007 	}
25008 	if (cc in this.mappings.area2reg) {
25009 		return this.mappings.area2reg[cc][area] || this.mappings.area2reg[cc]["default"];
25010 	} else {
25011 		return this.mappings.cc2reg[cc];
25012 	}
25013 };
25014 
25015 /**
25016  * Return the region that controls the dialing plan in the given
25017  * region. (ie. the "normalized phone region".)
25018  * 
25019  * @static
25020  * @package
25021  * @param {string} region the region code to normalize
25022  * @return {string} the normalized region code
25023  */
25024 PhoneLocale.prototype._normPhoneReg = function(region) {
25025 	var norm;
25026 	
25027 	// Map all NANP regions to the right region, so that they get parsed using the 
25028 	// correct state table
25029 	switch (region) {
25030 		case "US": // usa
25031 		case "CA": // canada
25032 		case "AG": // antigua and barbuda
25033 		case "BS": // bahamas
25034 		case "BB": // barbados
25035 		case "DM": // dominica
25036 		case "DO": // dominican republic
25037 		case "GD": // grenada
25038 		case "JM": // jamaica
25039 		case "KN": // st. kitts and nevis
25040 		case "LC": // st. lucia
25041 		case "VC": // st. vincent and the grenadines
25042 		case "TT": // trinidad and tobago
25043 		case "AI": // anguilla
25044 		case "BM": // bermuda
25045 		case "VG": // british virgin islands
25046 		case "KY": // cayman islands
25047 		case "MS": // montserrat
25048 		case "TC": // turks and caicos
25049 		case "AS": // American Samoa 
25050 		case "VI": // Virgin Islands, U.S.
25051 		case "PR": // Puerto Rico
25052 		case "MP": // Northern Mariana Islands
25053 		case "T:": // East Timor
25054 		case "GU": // Guam
25055 			norm = "US";
25056 			break;
25057 		
25058 		// these all use the Italian dialling plan
25059 		case "IT": // italy
25060 		case "SM": // san marino
25061 		case "VA": // vatican city
25062 			norm = "IT";
25063 			break;
25064 		
25065 		// all the French dependencies are on the French dialling plan
25066 		case "FR": // france
25067 		case "GF": // french guiana
25068 		case "MQ": // martinique
25069 		case "GP": // guadeloupe, 
25070 		case "BL": // saint barthélemy
25071 		case "MF": // saint martin
25072 		case "RE": // réunion, mayotte
25073 			norm = "FR";
25074 			break;
25075 		default:
25076 			norm = region;
25077 			break;
25078 	}	
25079 	return norm;
25080 };
25081 
25082 
25083 /*< PhoneHandlerFactory.js */
25084 /*
25085  * handler.js - Handle phone number parse states
25086  * 
25087  * Copyright © 2014-2015, JEDLSoft
25088  *
25089  * Licensed under the Apache License, Version 2.0 (the "License");
25090  * you may not use this file except in compliance with the License.
25091  * You may obtain a copy of the License at
25092  *
25093  *     http://www.apache.org/licenses/LICENSE-2.0
25094  *
25095  * Unless required by applicable law or agreed to in writing, software
25096  * distributed under the License is distributed on an "AS IS" BASIS,
25097  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25098  *
25099  * See the License for the specific language governing permissions and
25100  * limitations under the License.
25101  */
25102 
25103 
25104 /**
25105  * @class
25106  * @private
25107  * @constructor
25108  */
25109 var PhoneHandler = function () {
25110 	return this;
25111 };
25112 
25113 PhoneHandler.prototype = {
25114 	/**
25115 	 * @private
25116 	 * @param {string} number phone number
25117 	 * @param {Object} fields the fields that have been extracted so far
25118 	 * @param {Object} regionSettings settings used to parse the rest of the number
25119 	 */
25120 	processSubscriberNumber: function(number, fields, regionSettings) {
25121 		var last;
25122 		
25123 		last = number.search(/[xwtp,;]/i);	// last digit of the local number
25124 
25125 		if (last > -1) {
25126 			if (last > 0) {
25127 				fields.subscriberNumber = number.substring(0, last);
25128 			}
25129 			// strip x's which are there to indicate a break between the local subscriber number and the extension, but
25130 			// are not themselves a dialable character
25131 			fields.extension = number.substring(last).replace('x', '');
25132 		} else {
25133 			if (number.length) {
25134 				fields.subscriberNumber = number;
25135 			}
25136 		}
25137 		
25138 		if (regionSettings.plan.getFieldLength('maxLocalLength') &&
25139 				fields.subscriberNumber &&
25140 				fields.subscriberNumber.length > regionSettings.plan.getFieldLength('maxLocalLength')) {
25141 			fields.invalid = true;
25142 		}
25143 	},
25144 	/**
25145 	 * @private
25146 	 * @param {string} fieldName 
25147 	 * @param {number} length length of phone number
25148 	 * @param {string} number phone number
25149 	 * @param {number} currentChar currentChar to be parsed
25150 	 * @param {Object} fields the fields that have been extracted so far
25151 	 * @param {Object} regionSettings settings used to parse the rest of the number
25152 	 * @param {boolean} noExtractTrunk 
25153 	 */
25154 	processFieldWithSubscriberNumber: function(fieldName, length, number, currentChar, fields, regionSettings, noExtractTrunk) {
25155 		var ret, end;
25156 		
25157 		if (length !== undefined && length > 0) {
25158 			// fixed length
25159 			end = length;
25160 			if (regionSettings.plan.getTrunkCode() === "0" && number.charAt(0) === "0") {
25161 				end += regionSettings.plan.getTrunkCode().length;  // also extract the trunk access code
25162 			}
25163 		} else {
25164 			// variable length
25165 			// the setting is the negative of the length to add, so subtract to make it positive
25166 			end = currentChar + 1 - length;
25167 		}
25168 		
25169 		if (fields[fieldName] !== undefined) {
25170 			// we have a spurious recognition, because this number already contains that field! So, just put
25171 			// everything into the subscriberNumber as the default
25172 			this.processSubscriberNumber(number, fields, regionSettings);
25173 		} else {
25174 			fields[fieldName] = number.substring(0, end);
25175 			if (number.length > end) {
25176 				this.processSubscriberNumber(number.substring(end), fields, regionSettings);
25177 			}
25178 		}
25179 		
25180 		ret = {
25181 			number: ""
25182 		};
25183 
25184 		return ret;
25185 	},
25186 	/**
25187 	 * @private
25188 	 * @param {string} fieldName 
25189 	 * @param {number} length length of phone number
25190 	 * @param {string} number phone number
25191 	 * @param {number} currentChar currentChar to be parsed
25192 	 * @param {Object} fields the fields that have been extracted so far
25193 	 * @param {Object} regionSettings settings used to parse the rest of the number
25194 	 */
25195 	processField: function(fieldName, length, number, currentChar, fields, regionSettings) {
25196 		var ret = {}, end;
25197 		
25198 		if (length !== undefined && length > 0) {
25199 			// fixed length
25200 			end = length;
25201 			if (regionSettings.plan.getTrunkCode() === "0" && number.charAt(0) === "0") {
25202 				end += regionSettings.plan.getTrunkCode().length;  // also extract the trunk access code
25203 			}
25204 		} else {
25205 			// variable length
25206 			// the setting is the negative of the length to add, so subtract to make it positive
25207 			end = currentChar + 1 - length;
25208 		}
25209 		
25210 		if (fields[fieldName] !== undefined) {
25211 			// we have a spurious recognition, because this number already contains that field! So, just put
25212 			// everything into the subscriberNumber as the default
25213 			this.processSubscriberNumber(number, fields, regionSettings);
25214 			ret.number = "";
25215 		} else {
25216 			fields[fieldName] = number.substring(0, end);			
25217 			ret.number = (number.length > end) ? number.substring(end) : "";
25218 		}
25219 		
25220 		return ret;
25221 	},
25222 	/**
25223 	 * @private
25224 	 * @param {string} number phone number
25225 	 * @param {number} currentChar currentChar to be parsed
25226 	 * @param {Object} fields the fields that have been extracted so far
25227 	 * @param {Object} regionSettings settings used to parse the rest of the number
25228 	 */
25229 	trunk: function(number, currentChar, fields, regionSettings) {
25230 		var ret, trunkLength;
25231 		
25232 		if (fields.trunkAccess !== undefined) {
25233 			// What? We already have one? Okay, put the rest of this in the subscriber number as the default behaviour then.
25234 			this.processSubscriberNumber(number, fields, regionSettings);
25235 			number = "";
25236 		} else {
25237 			trunkLength = regionSettings.plan.getTrunkCode().length;
25238 			fields.trunkAccess = number.substring(0, trunkLength);
25239 			number = (number.length > trunkLength) ? number.substring(trunkLength) : "";
25240 		}
25241 		
25242 		ret = {
25243 			number: number
25244 		};
25245 		
25246 		return ret;
25247 	},
25248 	/**
25249 	 * @private
25250 	 * @param {string} number phone number
25251 	 * @param {number} currentChar currentChar to be parsed
25252 	 * @param {Object} fields the fields that have been extracted so far
25253 	 * @param {Object} regionSettings settings used to parse the rest of the number
25254 	 */
25255 	plus: function(number, currentChar, fields, regionSettings) {
25256 		var ret = {};
25257 		
25258 		if (fields.iddPrefix !== undefined) {
25259 			// What? We already have one? Okay, put the rest of this in the subscriber number as the default behaviour then.
25260 			this.processSubscriberNumber(number, fields, regionSettings);
25261 			ret.number = "";
25262 		} else {
25263 			// found the idd prefix, so save it and cause the function to parse the next part
25264 			// of the number with the idd table
25265 			fields.iddPrefix = number.substring(0, 1);
25266 	
25267 			ret = {
25268 				number: number.substring(1),
25269 				table: 'idd'    // shared subtable that parses the country code
25270 			};
25271 		}		
25272 		return ret;
25273 	},
25274 	/**
25275 	 * @private
25276 	 * @param {string} number phone number
25277 	 * @param {number} currentChar currentChar to be parsed
25278 	 * @param {Object} fields the fields that have been extracted so far
25279 	 * @param {Object} regionSettings settings used to parse the rest of the number
25280 	 */
25281 	idd: function(number, currentChar, fields, regionSettings) {
25282 		var ret = {};
25283 		
25284 		if (fields.iddPrefix !== undefined) {
25285 			// What? We already have one? Okay, put the rest of this in the subscriber number as the default behaviour then.
25286 			this.processSubscriberNumber(number, fields, regionSettings);
25287 			ret.number = "";
25288 		} else {
25289 			// found the idd prefix, so save it and cause the function to parse the next part
25290 			// of the number with the idd table
25291 			fields.iddPrefix = number.substring(0, currentChar+1);
25292 	
25293 			ret = {
25294 				number: number.substring(currentChar+1),
25295 				table: 'idd'    // shared subtable that parses the country code
25296 			};
25297 		}
25298 		
25299 		return ret;
25300 	},
25301 	/**
25302 	 * @private
25303 	 * @param {string} number phone number
25304 	 * @param {number} currentChar currentChar to be parsed
25305 	 * @param {Object} fields the fields that have been extracted so far
25306 	 * @param {Object} regionSettings settings used to parse the rest of the number
25307 	 */	
25308 	country: function(number, currentChar, fields, regionSettings) {
25309 		var ret, cc;
25310 		
25311 		// found the country code of an IDD number, so save it and cause the function to 
25312 		// parse the rest of the number with the regular table for this locale
25313 		fields.countryCode = number.substring(0, currentChar+1);
25314 		cc = fields.countryCode.replace(/[wWpPtT\+#\*]/g, ''); // fix for NOV-108200
25315 		// console.log("Found country code " + fields.countryCode + ". Switching to country " + locale.region + " to parse the rest of the number");
25316 		
25317 		ret = {
25318 			number: number.substring(currentChar+1),
25319 			countryCode: cc
25320 		};
25321 		
25322 		return ret;
25323 	},
25324 	/**
25325 	 * @private
25326 	 * @param {string} number phone number
25327 	 * @param {number} currentChar currentChar to be parsed
25328 	 * @param {Object} fields the fields that have been extracted so far
25329 	 * @param {Object} regionSettings settings used to parse the rest of the number
25330 	 */
25331 	cic: function(number, currentChar, fields, regionSettings) {
25332 		return this.processField('cic', regionSettings.plan.getFieldLength('cic'), number, currentChar, fields, regionSettings);
25333 	},
25334 	/**
25335 	 * @private
25336 	 * @param {string} number phone number
25337 	 * @param {number} currentChar currentChar to be parsed
25338 	 * @param {Object} fields the fields that have been extracted so far
25339 	 * @param {Object} regionSettings settings used to parse the rest of the number
25340 	 */
25341 	service: function(number, currentChar, fields, regionSettings) {
25342 		return this.processFieldWithSubscriberNumber('serviceCode', regionSettings.plan.getFieldLength('serviceCode'), number, currentChar, fields, regionSettings, false);
25343 	},
25344 	/**
25345 	 * @private
25346 	 * @param {string} number phone number
25347 	 * @param {number} currentChar currentChar to be parsed
25348 	 * @param {Object} fields the fields that have been extracted so far
25349 	 * @param {Object} regionSettings settings used to parse the rest of the number
25350 	 */
25351 	area: function(number, currentChar, fields, regionSettings) {
25352 		var ret, last, end, localLength;
25353 		
25354 		last = number.search(/[xwtp]/i);	// last digit of the local number
25355 		localLength = (last > -1) ? last : number.length;
25356 
25357 		if (regionSettings.plan.getFieldLength('areaCode') > 0) {
25358 			// fixed length
25359 			end = regionSettings.plan.getFieldLength('areaCode');
25360 			if (regionSettings.plan.getTrunkCode() === number.charAt(0)) {
25361 				end += regionSettings.plan.getTrunkCode().length;  // also extract the trunk access code
25362 				localLength -= regionSettings.plan.getTrunkCode().length;
25363 			}
25364 		} else {
25365 			// variable length
25366 			// the setting is the negative of the length to add, so subtract to make it positive
25367 			end = currentChar + 1 - regionSettings.plan.getFieldLength('areaCode');
25368 		}
25369 		
25370 		// substring() extracts the part of the string up to but not including the end character,
25371 		// so add one to compensate
25372 		if (regionSettings.plan.getFieldLength('maxLocalLength') !== undefined) {
25373 			if (fields.trunkAccess !== undefined || fields.mobilePrefix !== undefined ||
25374 					fields.countryCode !== undefined ||
25375 					localLength > regionSettings.plan.getFieldLength('maxLocalLength')) {
25376 				// too long for a local number by itself, or a different final state already parsed out the trunk
25377 				// or mobile prefix, then consider the rest of this number to be an area code + part of the subscriber number
25378 				fields.areaCode = number.substring(0, end);
25379 				if (number.length > end) {
25380 					this.processSubscriberNumber(number.substring(end), fields, regionSettings);
25381 				}
25382 			} else {
25383 				// shorter than the length needed for a local number, so just consider it a local number
25384 				this.processSubscriberNumber(number, fields, regionSettings);
25385 			}
25386 		} else {
25387 			fields.areaCode = number.substring(0, end);
25388 			if (number.length > end) {
25389 				this.processSubscriberNumber(number.substring(end), fields, regionSettings);
25390 			}
25391 		}
25392 		
25393 		// extensions are separated from the number by a dash in Germany
25394 		if (regionSettings.plan.getFindExtensions() !== undefined && fields.subscriberNumber !== undefined) {
25395 			var dash = fields.subscriberNumber.indexOf("-");
25396 			if (dash > -1) {
25397 				fields.subscriberNumber = fields.subscriberNumber.substring(0, dash);
25398 				fields.extension = fields.subscriberNumber.substring(dash+1);
25399 			}
25400 		}
25401 
25402 		ret = {
25403 			number: ""
25404 		};
25405 
25406 		return ret;
25407 	},
25408 	/**
25409 	 * @private
25410 	 * @param {string} number phone number
25411 	 * @param {number} currentChar currentChar to be parsed
25412 	 * @param {Object} fields the fields that have been extracted so far
25413 	 * @param {Object} regionSettings settings used to parse the rest of the number
25414 	 */
25415 	none: function(number, currentChar, fields, regionSettings) {
25416 		var ret;
25417 		
25418 		// this is a last resort function that is called when nothing is recognized.
25419 		// When this happens, just put the whole stripped number into the subscriber number
25420 			
25421 		if (number.length > 0) {
25422 			this.processSubscriberNumber(number, fields, regionSettings);
25423 			if (currentChar > 0 && currentChar < number.length) {
25424 				// if we were part-way through parsing, and we hit an invalid digit,
25425 				// indicate that the number could not be parsed properly
25426 				fields.invalid = true;
25427 			}
25428 		}
25429 		
25430 		ret = {
25431 			number:""
25432 		};
25433 		
25434 		return ret;
25435 	},
25436 	/**
25437 	 * @private
25438 	 * @param {string} number phone number
25439 	 * @param {number} currentChar currentChar to be parsed
25440 	 * @param {Object} fields the fields that have been extracted so far
25441 	 * @param {Object} regionSettings settings used to parse the rest of the number
25442 	 */
25443 	vsc: function(number, currentChar, fields, regionSettings) {
25444 		var ret, length, end;
25445 
25446 		if (fields.vsc === undefined) {
25447 			length = regionSettings.plan.getFieldLength('vsc') || 0;
25448 			if (length !== undefined && length > 0) {
25449 				// fixed length
25450 				end = length;
25451 			} else {
25452 				// variable length
25453 				// the setting is the negative of the length to add, so subtract to make it positive
25454 				end = currentChar + 1 - length;
25455 			}
25456 			
25457 			// found a VSC code (ie. a "star code"), so save it and cause the function to 
25458 			// parse the rest of the number with the same table for this locale
25459 			fields.vsc = number.substring(0, end);
25460 			number = (number.length > end) ? "^" + number.substring(end) : "";
25461 		} else {
25462 			// got it twice??? Okay, this is a bogus number then. Just put everything else into the subscriber number as the default
25463 			this.processSubscriberNumber(number, fields, regionSettings);
25464 			number = "";
25465 		}
25466 
25467 		// treat the rest of the number as if it were a completely new number
25468 		ret = {
25469 			number: number
25470 		};
25471 
25472 		return ret;
25473 	},
25474 	/**
25475 	 * @private
25476 	 * @param {string} number phone number
25477 	 * @param {number} currentChar currentChar to be parsed
25478 	 * @param {Object} fields the fields that have been extracted so far
25479 	 * @param {Object} regionSettings settings used to parse the rest of the number
25480 	 */
25481 	cell: function(number, currentChar, fields, regionSettings) {
25482 		return this.processFieldWithSubscriberNumber('mobilePrefix', regionSettings.plan.getFieldLength('mobilePrefix'), number, currentChar, fields, regionSettings, false);
25483 	},
25484 	/**
25485 	 * @private
25486 	 * @param {string} number phone number
25487 	 * @param {number} currentChar currentChar to be parsed
25488 	 * @param {Object} fields the fields that have been extracted so far
25489 	 * @param {Object} regionSettings settings used to parse the rest of the number
25490 	 */
25491 	personal: function(number, currentChar, fields, regionSettings) {
25492 		return this.processFieldWithSubscriberNumber('serviceCode', regionSettings.plan.getFieldLength('personal'), number, currentChar, fields, regionSettings, false);
25493 	},
25494 	/**
25495 	 * @private
25496 	 * @param {string} number phone number
25497 	 * @param {number} currentChar currentChar to be parsed
25498 	 * @param {Object} fields the fields that have been extracted so far
25499 	 * @param {Object} regionSettings settings used to parse the rest of the number
25500 	 */
25501 	emergency: function(number, currentChar, fields, regionSettings) {
25502 		return this.processFieldWithSubscriberNumber('emergency', regionSettings.plan.getFieldLength('emergency'), number, currentChar, fields, regionSettings, true);
25503 	},
25504 	/**
25505 	 * @private
25506 	 * @param {string} number phone number
25507 	 * @param {number} currentChar currentChar to be parsed
25508 	 * @param {Object} fields the fields that have been extracted so far
25509 	 * @param {Object} regionSettings settings used to parse the rest of the number
25510 	 */
25511 	premium: function(number, currentChar, fields, regionSettings) {
25512 		return this.processFieldWithSubscriberNumber('serviceCode', regionSettings.plan.getFieldLength('premium'), number, currentChar, fields, regionSettings, false);
25513 	},
25514 	/**
25515 	 * @private
25516 	 * @param {string} number phone number
25517 	 * @param {number} currentChar currentChar to be parsed
25518 	 * @param {Object} fields the fields that have been extracted so far
25519 	 * @param {Object} regionSettings settings used to parse the rest of the number
25520 	 */
25521 	special: function(number, currentChar, fields, regionSettings) {
25522 		return this.processFieldWithSubscriberNumber('serviceCode', regionSettings.plan.getFieldLength('special'), number, currentChar, fields, regionSettings, false);
25523 	},
25524 	/**
25525 	 * @private
25526 	 * @param {string} number phone number
25527 	 * @param {number} currentChar currentChar to be parsed
25528 	 * @param {Object} fields the fields that have been extracted so far
25529 	 * @param {Object} regionSettings settings used to parse the rest of the number
25530 	 */
25531 	service2: function(number, currentChar, fields, regionSettings) {
25532 		return this.processFieldWithSubscriberNumber('serviceCode', regionSettings.plan.getFieldLength('service2'), number, currentChar, fields, regionSettings, false);
25533 	},
25534 	/**
25535 	 * @private
25536 	 * @param {string} number phone number
25537 	 * @param {number} currentChar currentChar to be parsed
25538 	 * @param {Object} fields the fields that have been extracted so far
25539 	 * @param {Object} regionSettings settings used to parse the rest of the number
25540 	 */
25541 	service3: function(number, currentChar, fields, regionSettings) {
25542 		return this.processFieldWithSubscriberNumber('serviceCode', regionSettings.plan.getFieldLength('service3'), number, currentChar, fields, regionSettings, false);
25543 	},
25544 	/**
25545 	 * @private
25546 	 * @param {string} number phone number
25547 	 * @param {number} currentChar currentChar to be parsed
25548 	 * @param {Object} fields the fields that have been extracted so far
25549 	 * @param {Object} regionSettings settings used to parse the rest of the number
25550 	 */
25551 	service4: function(number, currentChar, fields, regionSettings) {
25552 		return this.processFieldWithSubscriberNumber('serviceCode', regionSettings.plan.getFieldLength('service4'), number, currentChar, fields, regionSettings, false);
25553 	},
25554 	/**
25555 	 * @private
25556 	 * @param {string} number phone number
25557 	 * @param {number} currentChar currentChar to be parsed
25558 	 * @param {Object} fields the fields that have been extracted so far
25559 	 * @param {Object} regionSettings settings used to parse the rest of the number
25560 	 */
25561 	cic2: function(number, currentChar, fields, regionSettings) {
25562 		return this.processField('cic', regionSettings.plan.getFieldLength('cic2'), number, currentChar, fields, regionSettings);
25563 	},
25564 	/**
25565 	 * @private
25566 	 * @param {string} number phone number
25567 	 * @param {number} currentChar currentChar to be parsed
25568 	 * @param {Object} fields the fields that have been extracted so far
25569 	 * @param {Object} regionSettings settings used to parse the rest of the number
25570 	 */
25571 	cic3: function(number, currentChar, fields, regionSettings) {
25572 		return this.processField('cic', regionSettings.plan.getFieldLength('cic3'), number, currentChar, fields, regionSettings);
25573 	},
25574 	/**
25575 	 * @private
25576 	 * @param {string} number phone number
25577 	 * @param {number} currentChar currentChar to be parsed
25578 	 * @param {Object} fields the fields that have been extracted so far
25579 	 * @param {Object} regionSettings settings used to parse the rest of the number
25580 	 */
25581 	start: function(number, currentChar, fields, regionSettings) {
25582 		// don't do anything except transition to the next state
25583 		return {
25584 			number: number
25585 		};
25586 	},
25587 	/**
25588 	 * @private
25589 	 * @param {string} number phone number
25590 	 * @param {number} currentChar currentChar to be parsed
25591 	 * @param {Object} fields the fields that have been extracted so far
25592 	 * @param {Object} regionSettings settings used to parse the rest of the number
25593 	 */
25594 	local: function(number, currentChar, fields, regionSettings) {
25595 		// in open dialling plans, we can tell that this number is a local subscriber number because it
25596 		// starts with a digit that indicates as such
25597 		this.processSubscriberNumber(number, fields, regionSettings);
25598 		return {
25599 			number: ""
25600 		};
25601 	}
25602 };
25603 
25604 // context-sensitive handler
25605 /**
25606  * @class
25607  * @private
25608  * @extends PhoneHandler
25609  * @constructor
25610  */
25611 var CSStateHandler = function () {
25612 	return this;
25613 };
25614 
25615 CSStateHandler.prototype = new PhoneHandler();
25616 CSStateHandler.prototype.special = function (number, currentChar, fields, regionSettings) {
25617 	var ret;
25618 	
25619 	// found a special area code that is both a node and a leaf. In
25620 	// this state, we have found the leaf, so chop off the end 
25621 	// character to make it a leaf.
25622 	if (number.charAt(0) === "0") {
25623 		fields.trunkAccess = number.charAt(0);
25624 		fields.areaCode = number.substring(1, currentChar);
25625 	} else {
25626 		fields.areaCode = number.substring(0, currentChar);
25627 	}
25628 	this.processSubscriberNumber(number.substring(currentChar), fields, regionSettings);
25629 	
25630 	ret = {
25631 		number: ""
25632 	};
25633 	
25634 	return ret;
25635 };
25636 
25637 /**
25638  * @class
25639  * @private
25640  * @extends PhoneHandler
25641  * @constructor
25642  */
25643 var USStateHandler = function () {
25644 	return this;
25645 };
25646 
25647 USStateHandler.prototype = new PhoneHandler();
25648 USStateHandler.prototype.vsc = function (number, currentChar, fields, regionSettings) {
25649 	var ret;
25650 
25651 	// found a VSC code (ie. a "star code")
25652 	fields.vsc = number;
25653 
25654 	// treat the rest of the number as if it were a completely new number
25655 	ret = {
25656 		number: ""
25657 	};
25658 
25659 	return ret;
25660 };
25661 
25662 /**
25663  * Creates a phone handler instance that is correct for the locale. Phone handlers are
25664  * used to handle parsing of the various fields in a phone number.
25665  * 
25666  * @protected
25667  * @static
25668  * @return {PhoneHandler} the correct phone handler for the locale
25669  */
25670 var PhoneHandlerFactory = function (locale, plan) {
25671 	if (plan.getContextFree() !== undefined && typeof(plan.getContextFree()) === 'boolean' && plan.getContextFree() === false) {
25672 		return new CSStateHandler();
25673 	}
25674 	var region = (locale && locale.getRegion()) || "ZZ";
25675 	switch (region) {
25676 	case 'US':
25677 		return new USStateHandler();
25678 		break;
25679 	default:
25680 		return new PhoneHandler();
25681 	}
25682 };
25683 
25684 
25685 /*< PhoneNumber.js */
25686 /*
25687  * phonenum.js - Represent a phone number.
25688  * 
25689  * Copyright © 2014-2015, JEDLSoft
25690  *
25691  * Licensed under the Apache License, Version 2.0 (the "License");
25692  * you may not use this file except in compliance with the License.
25693  * You may obtain a copy of the License at
25694  *
25695  *     http://www.apache.org/licenses/LICENSE-2.0
25696  *
25697  * Unless required by applicable law or agreed to in writing, software
25698  * distributed under the License is distributed on an "AS IS" BASIS,
25699  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25700  *
25701  * See the License for the specific language governing permissions and
25702  * limitations under the License.
25703  */
25704 
25705 /*
25706 !depends 
25707 ilib.js
25708 NumberingPlan.js
25709 PhoneLocale.js
25710 PhoneHandlerFactory.js
25711 Utils.js
25712 JSUtils.js
25713 */
25714 
25715 // !data states idd mnc
25716 
25717 
25718 /**
25719  * @class
25720  * Create a new phone number instance that parses the phone number parameter for its 
25721  * constituent parts, and store them as separate fields in the returned object.
25722  * 
25723  * The options object may include any of these properties:
25724  * 
25725  * <ul>
25726  * <li><i>locale</i> The locale with which to parse the number. This gives a clue as to which
25727  * numbering plan to use.
25728  * <li><i>mcc</i> The mobile carrier code (MCC) associated with the carrier that the phone is 
25729  * currently connected to, if known. This also can give a clue as to which numbering plan to
25730  * use
25731  * <li>onLoad - a callback function to call when this instance is fully 
25732  * loaded. When the onLoad option is given, this class will attempt to
25733  * load any missing locale data using the ilib loader callback.
25734  * When the constructor is done (even if the data is already preassembled), the 
25735  * onLoad function is called with the current instance as a parameter, so this
25736  * callback can be used with preassembled or dynamic loading or a mix of the two.
25737  * <li>sync - tell whether to load any missing locale data synchronously or 
25738  * asynchronously. If this option is given as "false", then the "onLoad"
25739  * callback must be given, as the instance returned from this constructor will
25740  * not be usable for a while.
25741  * <li><i>loadParams</i> - an object containing parameters to pass to the 
25742  * loader callback function when locale data is missing. The parameters are not
25743  * interpretted or modified in any way. They are simply passed along. The object 
25744  * may contain any property/value pairs as long as the calling code is in
25745  * agreement with the loader callback function as to what those parameters mean.
25746  * </ul>
25747  * 
25748  * This function is locale-sensitive, and will assume any number passed to it is
25749  * appropriate for the given locale. If the MCC is given, this method will assume
25750  * that numbers without an explicit country code have been dialled within the country
25751  * given by the MCC. This affects how things like area codes are parsed. If the MCC
25752  * is not given, this method will use the given locale to determine the country
25753  * code. If the locale is not explicitly given either, then this function uses the 
25754  * region of current locale as the default.<p>
25755  * 
25756  * The input number may contain any formatting characters for the given locale. Each 
25757  * field that is returned in the json object is a simple string of digits with
25758  * all formatting and whitespace characters removed.<p>
25759  * 
25760  * The number is decomposed into its parts, regardless if the number
25761  * contains formatting characters. If a particular part cannot be extracted from given 
25762  * number, the field will not be returned as a field in the object. If no fields can be
25763  * extracted from the number at all, then all digits found in the string will be 
25764  * returned in the subscriberNumber field. If the number parameter contains no 
25765  * digits, an empty object is returned.<p>
25766  * 
25767  * This instance can contain any of the following fields after parsing is done:
25768  * 
25769  * <ul>
25770  * <li>vsc - if this number starts with a VSC (Vertical Service Code, or "star code"), this field will contain the star and the code together
25771  * <li>iddPrefix - the prefix for international direct dialing. This can either be in the form of a plus character or the IDD access code for the given locale
25772  * <li>countryCode - if this number is an international direct dial number, this is the country code
25773  * <li>cic - for "dial-around" services (access to other carriers), this is the prefix used as the carrier identification code
25774  * <li>emergency - an emergency services number
25775  * <li>mobilePrefix - prefix that introduces a mobile phone number
25776  * <li>trunkAccess - trunk access code (long-distance access)
25777  * <li>serviceCode - like a geographic area code, but it is a required prefix for various services
25778  * <li>areaCode - geographic area codes
25779  * <li>subscriberNumber - the unique number of the person or company that pays for this phone line
25780  * <li>extension - in some countries, extensions are dialed directly without going through an operator or a voice prompt system. If the number includes an extension, it is given in this field.
25781  * <li>invalid - this property is added and set to true if the parser found that the number is invalid in the numbering plan for the country. This method will make its best effort at parsing, but any digits after the error will go into the subscriberNumber field
25782  * </ul>
25783  * 
25784  * The following rules determine how the number is parsed:
25785  * 
25786  * <ol>
25787  * <li>If the number starts with a character that is alphabetic instead of numeric, do
25788  * not parse the number at all. There is a good chance that it is not really a phone number.
25789  * In this case, an empty instance will be returned.
25790  * <li>If the phone number uses the plus notation or explicitly uses the international direct
25791  * dialing prefix for the given locale, then the country code is identified in 
25792  * the number. The rules of given locale are used to parse the IDD prefix, and then the rules
25793  * of the country in the prefix are used to parse the rest of the number.
25794  * <li>If a country code is provided as an argument to the function call, use that country's
25795  * parsing rules for the number. This is intended for programs like a Contacts application that 
25796  * know what the country is of the person that owns the phone number and can pass that on as 
25797  * a hint.
25798  * <li>If the appropriate locale cannot be easily determined, default to using the rules 
25799  * for the current user's region.
25800  * </ol>
25801  * 
25802  * Example: parsing the number "+49 02101345345-78" will give the following properties in the
25803  * resulting phone number instance:
25804  * 
25805  * <pre>
25806  *      {
25807  *        iddPrefix: "+",
25808  *        countryCode: "49",
25809  *        areaCode: "02101",
25810  *        subscriberNumber: "345345",
25811  *        extension: "78"
25812  *      }
25813  * </pre>
25814  *  
25815  * Note that in this example, because international direct dialing is explicitly used 
25816  * in the number, the part of this number after the IDD prefix and country code will be 
25817  * parsed exactly the same way in all locales with German rules (country code 49).
25818  *  
25819  * Regions currently supported are:
25820  *  
25821  * <ul>
25822  * <li>NANP (North American Numbering Plan) countries - USA, Canada, Bermuda, various Caribbean nations
25823  * <li>UK
25824  * <li>Republic of Ireland
25825  * <li>Germany
25826  * <li>France
25827  * <li>Spain
25828  * <li>Italy
25829  * <li>Mexico
25830  * <li>India
25831  * <li>People's Republic of China
25832  * <li>Netherlands
25833  * <li>Belgium
25834  * <li>Luxembourg
25835  * <li>Australia
25836  * <li>New Zealand
25837  * <li>Singapore
25838  * <li>Korea
25839  * <li>Japan
25840  * <li>Russia
25841  * <li>Brazil
25842  * </ul>
25843  * 
25844  * @constructor
25845  * @param {!string|PhoneNumber} number A free-form phone number to be parsed, or another phone
25846  * number instance to copy
25847  * @param {Object=} options options that guide the parser in parsing the number
25848  */
25849 var PhoneNumber = function(number, options) {
25850 	var stateData,
25851 		regionSettings;
25852 
25853 	this.sync = true;
25854 	this.loadParams = {};
25855 	
25856 	if (!number || (typeof number === "string" && number.length === 0)) {
25857 		return this;
25858 	}
25859 
25860 	if (options) {
25861 		if (typeof(options.sync) === 'boolean') {
25862 			this.sync = options.sync;
25863 		}
25864 
25865 		if (options.loadParams) {
25866 			this.loadParams = options.loadParams;
25867 		}
25868 
25869 		if (typeof(options.onLoad) === 'function') {
25870 			/** 
25871 			 * @private
25872 			 * @type {function(PhoneNumber)} 
25873 			 */
25874 			this.onLoad = options.onLoad;
25875 		}
25876 	}
25877 
25878 	if (typeof number === "object") {
25879 		/**
25880 		 * The vertical service code. These are codes that typically
25881 		 * start with a star or hash, like "*69" for "dial back the 
25882 		 * last number that called me".
25883 		 * @type {string|undefined} 
25884 		 */
25885 		this.vsc = number.vsc;
25886 
25887 		/**
25888 		 * The international direct dialing prefix. This is always
25889 		 * followed by the country code. 
25890 		 * @type {string} 
25891 		 */
25892 		this.iddPrefix = number.iddPrefix;
25893 		
25894 		/**
25895 		 * The unique IDD country code for the country where the
25896 		 * phone number is serviced. 
25897 		 * @type {string|undefined} 
25898 		 */
25899 		this.countryCode = number.countryCode;
25900 		
25901 		/**
25902 		 * The digits required to access the trunk. 
25903 		 * @type {string|undefined} 
25904 		 */
25905 		this.trunkAccess = number.trunkAccess;
25906 		
25907 		/**
25908 		 * The carrier identification code used to identify 
25909 		 * alternate long distance or international carriers. 
25910 		 * @type {string|undefined} 
25911 		 */
25912 		this.cic = number.cic;
25913 		
25914 		/**
25915 		 * Identifies an emergency number that is typically
25916 		 * short, such as "911" in North America or "112" in
25917 		 * many other places in the world. 
25918 		 * @type {string|undefined} 
25919 		 */
25920 		this.emergency = number.emergency;
25921 		
25922 		/**
25923 		 * The prefix of the subscriber number that indicates
25924 		 * that this is the number of a mobile phone. 
25925 		 * @type {string|undefined} 
25926 		 */
25927 		this.mobilePrefix = number.mobilePrefix;
25928 		
25929 		/**
25930 		 * The prefix that identifies this number as commercial
25931 		 * service number. 
25932 		 * @type {string|undefined} 
25933 		 */
25934 		this.serviceCode = number.serviceCode;
25935 		
25936 		/**
25937 		 * The area code prefix of a land line number. 
25938 		 * @type {string|undefined} 
25939 		 */
25940 		this.areaCode = number.areaCode;
25941 		
25942 		/**
25943 		 * The unique number associated with the subscriber
25944 		 * of this phone. 
25945 		 * @type {string|undefined} 
25946 		 */
25947 		this.subscriberNumber = number.subscriberNumber;
25948 		
25949 		/**
25950 		 * The direct dial extension number. 
25951 		 * @type {string|undefined} 
25952 		 */
25953 		this.extension = number.extension;
25954 		
25955 		/**
25956 		 * @private
25957 		 * @type {boolean} 
25958 		 */
25959 		this.invalid = number.invalid;
25960 
25961 		if (number.plan && number.locale) {
25962 			/** 
25963 			 * @private
25964 			 * @type {NumberingPlan} 
25965 			 */
25966 			this.plan = number.plan;
25967 			
25968 			/** 
25969 			 * @private
25970 			 * @type {PhoneLocale} 
25971 			 */
25972 			this.locale = number.locale;
25973 	
25974 			/** 
25975 			 * @private
25976 			 * @type {NumberingPlan} 
25977 			 */
25978 			this.destinationPlan = number.destinationPlan;
25979 			
25980 			/** 
25981 			 * @private
25982 			 * @type {PhoneLocale} 
25983 			 */
25984 			this.destinationLocale = number.destinationLocale;
25985 	
25986 			if (options && typeof(options.onLoad) === 'function') {
25987 				options.onLoad(this);
25988 			}
25989 			return;
25990 		}
25991 	}
25992 
25993 	new PhoneLocale({
25994 		locale: options && options.locale,
25995 		mcc: options && options.mcc,
25996 		sync: this.sync,
25997 		loadParams: this.loadParams,
25998 		onLoad: ilib.bind(this, function(loc) {
25999 			this.locale = this.destinationLocale = loc;
26000 			new NumberingPlan({
26001 				locale: this.locale,
26002 				sync: this.sync,
26003 				loadParms: this.loadParams,
26004 				onLoad: ilib.bind(this, function (plan) {
26005 					this.plan = this.destinationPlan = plan;
26006 			
26007 					if (typeof number === "object") {
26008 						// the copy constructor code above did not find the locale 
26009 						// or plan before, but now they are loaded, so we can return 
26010 						// already without going further
26011 						return;
26012 					}
26013 					Utils.loadData({
26014 						name: "states.json",
26015 						object: PhoneNumber,
26016 						locale: this.locale,
26017 						sync: this.sync,
26018 						loadParams: JSUtils.merge(this.loadParams, {
26019 							returnOne: true
26020 						}),
26021 						callback: ilib.bind(this, function (stdata) {
26022 							if (!stdata) {
26023 								stdata = PhoneNumber._defaultStates;
26024 							}
26025 		
26026 							stateData = stdata;
26027 
26028 							regionSettings = {
26029 								stateData: stateData,
26030 								plan: plan,
26031 								handler: PhoneHandlerFactory(this.locale, plan)
26032 							};
26033 							
26034 							// use ^ to indicate the beginning of the number, because certain things only match at the beginning
26035 							number = "^" + number.replace(/\^/g, '');
26036 							number = PhoneNumber._stripFormatting(number);
26037 
26038 							this._parseNumber(number, regionSettings, options);
26039 						})
26040 					});
26041 				})
26042 			});
26043 		})
26044 	});
26045 };
26046 
26047 /**
26048  * Parse an International Mobile Subscriber Identity (IMSI) number into its 3 constituent parts:
26049  * 
26050  * <ol>
26051  * <li>mcc - Mobile Country Code, which identifies the country where the phone is currently receiving 
26052  * service.
26053  * <li>mnc - Mobile Network Code, which identifies the carrier which is currently providing service to the phone 
26054  * <li>msin - Mobile Subscription Identifier Number. This is a unique number identifying the mobile phone on 
26055  * the network, which usually maps to an account/subscriber in the carrier's database.
26056  * </ol>
26057  * 
26058  * Because this function may need to load data to identify the above parts, you can pass an options
26059  * object that controls how the data is loaded. The options may contain any of the following properties:
26060  *
26061  * <ul>
26062  * <li>onLoad - a callback function to call when the parsing is done. When the onLoad option is given, 
26063  * this method will attempt to load the locale data using the ilib loader callback. When it is done
26064  * (even if the data is already preassembled), the onLoad function is called with the parsing results
26065  * as a parameter, so this callback can be used with preassembled or dynamic, synchronous or 
26066  * asynchronous loading or a mix of the above.
26067  * <li>sync - tell whether to load any missing locale data synchronously or asynchronously. If this 
26068  * option is given as "false", then the "onLoad" callback must be given, as the results returned from 
26069  * this constructor will not be usable for a while.
26070  * <li><i>loadParams</i> - an object containing parameters to pass to the loader callback function 
26071  * when locale data is missing. The parameters are not interpretted or modified in any way. They are 
26072  * simply passed along. The object may contain any property/value pairs as long as the calling code is in
26073  * agreement with the loader callback function as to what those parameters mean.
26074  * </ul>
26075  *
26076  * @static
26077  * @param {string} imsi IMSI number to parse
26078  * @param {Object} options options controlling the loading of the locale data
26079  * @return {{mcc:string,mnc:string,msin:string}|undefined} components of the IMSI number, when the locale data
26080  * is loaded synchronously, or undefined if asynchronous
26081  */
26082 PhoneNumber.parseImsi = function(imsi, options) {
26083 	var sync = true,
26084 		loadParams = {},
26085 		fields = {};
26086 	
26087 	if (!imsi) {
26088 		return undefined;
26089 	}
26090 
26091 	if (options) {
26092 		if (typeof(options.sync) !== 'undefined') {
26093 			sync = (options.sync == true);
26094 		}
26095 		
26096 		if (options.loadParams) {
26097 			loadParams = options.loadParams;
26098 		}
26099 	}	
26100 
26101 	if (ilib.data.mnc) {
26102 		fields = PhoneNumber._parseImsi(ilib.data.mnc, imsi);
26103 		
26104 		if (options && typeof(options.onLoad) === 'function') {
26105 			options.onLoad(fields);
26106 		}
26107 	} else {
26108 		Utils.loadData({
26109 			name: "mnc.json", 
26110 			object: PhoneNumber, 
26111 			nonlocale: true, 
26112 			sync: sync, 
26113 			loadParams: loadParams, 
26114 			callback: ilib.bind(this, function(data) {
26115 				ilib.data.mnc = data;
26116 				fields = PhoneNumber._parseImsi(data, imsi);
26117 				
26118 				if (options && typeof(options.onLoad) === 'function') {
26119 					options.onLoad(fields);
26120 				}
26121 			})
26122 		});
26123 	}
26124 	return fields;
26125 };
26126 
26127 
26128 /**
26129  * @static
26130  * @protected
26131  */
26132 PhoneNumber._parseImsi = function(data, imsi) {
26133 	var ch, 
26134 		i,
26135 		currentState, 
26136 		end, 
26137 		handlerMethod,
26138 		state = 0,
26139 		newState,
26140 		fields = {},
26141 		lastLeaf,
26142 		consumed = 0;
26143 	
26144 	currentState = data;
26145 	if (!currentState) {
26146 		// can't parse anything
26147 		return undefined;
26148 	}
26149 	
26150 	i = 0;
26151 	while (i < imsi.length) {
26152 		ch = PhoneNumber._getCharacterCode(imsi.charAt(i));
26153 		// console.info("parsing char " + imsi.charAt(i) + " code: " + ch);
26154 		if (ch >= 0) {
26155 			newState = currentState.s && currentState.s[ch];
26156 			
26157 			if (typeof(newState) === 'object') {
26158 				if (typeof(newState.l) !== 'undefined') {
26159 					// save for latter if needed
26160 					lastLeaf = newState;
26161 					consumed = i;
26162 				}
26163 				// console.info("recognized digit " + ch + " continuing...");
26164 				// recognized digit, so continue parsing
26165 				currentState = newState;
26166 				i++;
26167 			} else {
26168 				if ((typeof(newState) === 'undefined' || newState === 0 ||
26169 					(typeof(newState) === 'object' && typeof(newState.l) === 'undefined')) &&
26170 					 lastLeaf) {
26171 					// this is possibly a look-ahead and it didn't work... 
26172 					// so fall back to the last leaf and use that as the
26173 					// final state
26174 					newState = lastLeaf;
26175 					i = consumed;
26176 				}
26177 				
26178 				if ((typeof(newState) === 'number' && newState) ||
26179 					(typeof(newState) === 'object' && typeof(newState.l) !== 'undefined')) {
26180 					// final state
26181 					var stateNumber = typeof(newState) === 'number' ? newState : newState.l;
26182 					handlerMethod = PhoneNumber._states[stateNumber];
26183 
26184 					// console.info("reached final state " + newState + " handler method is " + handlerMethod + " and i is " + i);
26185 	
26186 					// deal with syntactic ambiguity by using the "special" end state instead of "area"
26187 					if ( handlerMethod === "area" ) {
26188 						end = i+1;
26189 					} else {
26190 						// unrecognized imsi, so just assume the mnc is 3 digits
26191 						end = 6;
26192 					}
26193 					
26194 					fields.mcc = imsi.substring(0,3);
26195 					fields.mnc = imsi.substring(3,end);
26196 					fields.msin = imsi.substring(end);
26197 	
26198 					return fields;
26199 				} else {
26200 					// parse error
26201 					if (imsi.length >= 6) {
26202 						fields.mcc = imsi.substring(0,3);
26203 						fields.mnc = imsi.substring(3,6);
26204 						fields.msin = imsi.substring(6);
26205 					}
26206 					return fields;
26207 				}
26208 			}
26209 		} else if (ch === -1) {
26210 			// non-transition character, continue parsing in the same state
26211 			i++;
26212 		} else {
26213 			// should not happen
26214 			// console.info("skipping character " + ch);
26215 			// not a digit, plus, pound, or star, so this is probably a formatting char. Skip it.
26216 			i++;
26217 		}
26218 	}
26219 		
26220 	if (i >= imsi.length && imsi.length >= 6) {
26221 		// we reached the end of the imsi, but did not finish recognizing anything. 
26222 		// Default to last resort and assume 3 digit mnc
26223 		fields.mcc = imsi.substring(0,3);
26224 		fields.mnc = imsi.substring(3,6);
26225 		fields.msin = imsi.substring(6);
26226 	} else {
26227 		// unknown or not enough characters for a real imsi 
26228 		fields = undefined;
26229 	}
26230 		
26231 	// console.info("Globalization.Phone.parseImsi: final result is: " + JSON.stringify(fields));
26232 	return fields;
26233 };
26234 
26235 /**
26236  * @static
26237  * @private
26238  */
26239 PhoneNumber._stripFormatting = function(str) {
26240 	var ret = "";
26241 	var i;
26242 
26243 	for (i = 0; i < str.length; i++) {
26244 		if (PhoneNumber._getCharacterCode(str.charAt(i)) >= -1) {
26245 			ret += str.charAt(i);
26246 		}
26247 	}
26248 	return ret;
26249 };
26250 
26251 /**
26252  * @static
26253  * @protected
26254  */
26255 PhoneNumber._getCharacterCode = function(ch) {
26256 	if (ch >= '0' && ch <= '9') {
26257 			return ch - '0';
26258 		}
26259 	switch (ch) {
26260 	case '+':
26261 		return 10;
26262 	case '*':
26263 		return 11;
26264 	case '#':
26265 		return 12;
26266 	case '^':
26267 		return 13;
26268 	case 'p':		// pause chars
26269 	case 'P':
26270 	case 't':
26271 	case 'T':
26272 	case 'w':
26273 	case 'W':
26274 		return -1;
26275 	case 'x':
26276 	case 'X':
26277 	case ',':
26278 	case ';':		// extension char
26279 		return -1;
26280 	}
26281 	return -2;
26282 };
26283 
26284 /**
26285  * @private
26286  */
26287 PhoneNumber._states = [
26288 	"none",
26289 	"unknown",
26290 	"plus",
26291 	"idd",
26292 	"cic",
26293 	"service",
26294 	"cell",
26295 	"area",
26296 	"vsc",
26297 	"country",
26298 	"personal",
26299 	"special",
26300 	"trunk",
26301 	"premium",
26302 	"emergency",
26303 	"service2",
26304 	"service3",
26305 	"service4",
26306 	"cic2",
26307 	"cic3",
26308 	"start",
26309 	"local"
26310 ];
26311 
26312 /**
26313  * @private
26314  */
26315 PhoneNumber._fieldOrder = [
26316 	"vsc",
26317 	"iddPrefix",
26318 	"countryCode",
26319 	"trunkAccess",
26320 	"cic",
26321 	"emergency",
26322 	"mobilePrefix",
26323 	"serviceCode",
26324 	"areaCode",
26325 	"subscriberNumber",
26326 	"extension"
26327 ];
26328 
26329 PhoneNumber._defaultStates = {
26330 	"s": [
26331         0,
26332 		21,  // 1 -> local
26333         21,  // 2 -> local
26334         21,  // 3 -> local
26335         21,  // 4 -> local
26336         21,  // 5 -> local
26337         21,  // 6 -> local
26338         21,  // 7 -> local
26339         21,  // 8 -> local
26340         21,  // 9 -> local
26341         0,0,0,
26342 	    { // ^
26343 	    	"s": [
26344 				{ // ^0
26345 					"s": [3], // ^00 -> idd
26346 					"l": 12   // ^0  -> trunk
26347 				},
26348 				21,  // ^1 -> local
26349 	            21,  // ^2 -> local
26350 	            21,  // ^3 -> local
26351 	            21,  // ^4 -> local
26352 	            21,  // ^5 -> local
26353 	            21,  // ^6 -> local
26354 	            21,  // ^7 -> local
26355 	            21,  // ^8 -> local
26356 	            21,  // ^9 -> local
26357 	            2    // ^+ -> plus
26358 	        ]
26359 	    }
26360 	]
26361 };
26362 
26363 PhoneNumber.prototype = {
26364 	/**
26365 	 * @protected
26366 	 * @param {string} number
26367 	 * @param {Object} regionData
26368 	 * @param {Object} options
26369 	 * @param {string} countryCode
26370 	 */
26371 	_parseOtherCountry: function(number, regionData, options, countryCode) {
26372 		new PhoneLocale({
26373 			locale: this.locale,
26374 			countryCode: countryCode,
26375 			sync: this.sync,
26376 			loadParms: this.loadParams,
26377 			onLoad: ilib.bind(this, function (loc) {
26378 				/*
26379 				 * this.locale is the locale where this number is being parsed,
26380 				 * and is used to parse the IDD prefix, if any, and this.destinationLocale is 
26381 				 * the locale of the rest of this number after the IDD prefix.
26382 				 */
26383 				/** @type {PhoneLocale} */
26384 				this.destinationLocale = loc;
26385 
26386 				Utils.loadData({
26387 					name: "states.json",
26388 					object: PhoneNumber,
26389 					locale: this.destinationLocale,
26390 					sync: this.sync,
26391 					loadParams: JSUtils.merge(this.loadParams, {
26392 						returnOne: true
26393 					}),
26394 					callback: ilib.bind(this, function (stateData) {
26395 						if (!stateData) {
26396 							stateData = PhoneNumber._defaultStates;
26397 						}
26398 						
26399 						new NumberingPlan({
26400 							locale: this.destinationLocale,
26401 							sync: this.sync,
26402 							loadParms: this.loadParams,
26403 							onLoad: ilib.bind(this, function (plan) {
26404 								/*
26405 								 * this.plan is the plan where this number is being parsed,
26406 								 * and is used to parse the IDD prefix, if any, and this.destinationPlan is 
26407 								 * the plan of the rest of this number after the IDD prefix in the 
26408 								 * destination locale.
26409 								 */
26410 								/** @type {NumberingPlan} */
26411 								this.destinationPlan = plan;
26412 
26413 								var regionSettings = {
26414 									stateData: stateData,
26415 									plan: plan,
26416 									handler: PhoneHandlerFactory(this.destinationLocale, plan)
26417 								};
26418 								
26419 								// for plans that do not skip the trunk code when dialing from
26420 								// abroad, we need to treat the number from here on in as if it 
26421 								// were parsing a local number from scratch. That way, the parser
26422 								// does not get confused between parts of the number at the
26423 								// beginning of the number, and parts in the middle.
26424 								if (!plan.getSkipTrunk()) {
26425 									number = '^' + number;
26426 								}
26427 									
26428 								// recursively call the parser with the new states data
26429 								// to finish the parsing
26430 								this._parseNumber(number, regionSettings, options);
26431 							})
26432 						});
26433 					})
26434 				});
26435 			})
26436 		});
26437 	},
26438 	
26439 	/**
26440 	 * @protected
26441 	 * @param {string} number
26442 	 * @param {Object} regionData
26443 	 * @param {Object} options
26444 	 */
26445 	_parseNumber: function(number, regionData, options) {
26446 		var i, ch,
26447 			regionSettings,
26448 			newState,
26449 			dot,
26450 			handlerMethod,
26451 			result,
26452 			currentState = regionData.stateData,
26453 			lastLeaf = undefined,
26454 			consumed = 0;
26455 
26456 		regionSettings = regionData;
26457 		dot = 14; // special transition which matches all characters. See AreaCodeTableMaker.java
26458 
26459 		i = 0;
26460 		while (i < number.length) {
26461 			ch = PhoneNumber._getCharacterCode(number.charAt(i));
26462 			if (ch >= 0) {
26463 				// newState = stateData.states[state][ch];
26464 				newState = currentState.s && currentState.s[ch];
26465 				
26466 				if (!newState && currentState.s && currentState.s[dot]) {
26467 					newState = currentState.s[dot];
26468 				}
26469 				
26470 				if (typeof(newState) === 'object' && i+1 < number.length) {
26471 					if (typeof(newState.l) !== 'undefined') {
26472 						// this is a leaf node, so save that for later if needed
26473 						lastLeaf = newState;
26474 						consumed = i;
26475 					}
26476 					// console.info("recognized digit " + ch + " continuing...");
26477 					// recognized digit, so continue parsing
26478 					currentState = newState;
26479 					i++;
26480 				} else {
26481 					if ((typeof(newState) === 'undefined' || newState === 0 ||
26482 						(typeof(newState) === 'object' && typeof(newState.l) === 'undefined')) &&
26483 						 lastLeaf) {
26484 						// this is possibly a look-ahead and it didn't work... 
26485 						// so fall back to the last leaf and use that as the
26486 						// final state
26487 						newState = lastLeaf;
26488 						i = consumed;
26489 						consumed = 0;
26490 						lastLeaf = undefined;
26491 					}
26492 					
26493 					if ((typeof(newState) === 'number' && newState) ||
26494 						(typeof(newState) === 'object' && typeof(newState.l) !== 'undefined')) {
26495 						// final state
26496 						var stateNumber = typeof(newState) === 'number' ? newState : newState.l;
26497 						handlerMethod = PhoneNumber._states[stateNumber];
26498 						
26499 						if (number.charAt(0) === '^') {
26500 							result = regionSettings.handler[handlerMethod](number.slice(1), i-1, this, regionSettings);
26501 						} else {
26502 							result = regionSettings.handler[handlerMethod](number, i, this, regionSettings);
26503 						}
26504 		
26505 						// reparse whatever is left
26506 						number = result.number;
26507 						i = consumed = 0;
26508 						lastLeaf = undefined;
26509 						
26510 						//console.log("reparsing with new number: " +  number);
26511 						currentState = regionSettings.stateData;
26512 						// if the handler requested a special sub-table, use it for this round of parsing,
26513 						// otherwise, set it back to the regular table to continue parsing
26514 	
26515 						if (result.countryCode !== undefined) {
26516 							this._parseOtherCountry(number, regionData, options, result.countryCode);
26517 							// don't process any further -- let the work be done in the onLoad callbacks
26518 							return;
26519 						} else if (result.table !== undefined) {
26520 							Utils.loadData({
26521 								name: result.table + ".json",
26522 								object: PhoneNumber,
26523 								nonlocale: true,
26524 								sync: this.sync,
26525 								loadParams: this.loadParams,
26526 								callback: ilib.bind(this, function (data) {
26527 									if (!data) {
26528 										data = PhoneNumber._defaultStates;
26529 									}
26530 	
26531 									regionSettings = {
26532 										stateData: data,
26533 										plan: regionSettings.plan,
26534 										handler: regionSettings.handler
26535 									};
26536 									
26537 									// recursively call the parser with the new states data
26538 									// to finish the parsing
26539 									this._parseNumber(number, regionSettings, options);
26540 								})
26541 							});
26542 							// don't process any further -- let the work be done in the onLoad callbacks
26543 							return;
26544 						} else if (result.skipTrunk !== undefined) {
26545 							ch = PhoneNumber._getCharacterCode(regionSettings.plan.getTrunkCode());
26546 							currentState = currentState.s && currentState.s[ch];
26547 						}
26548 					} else {
26549 						handlerMethod = (typeof(newState) === 'number') ? "none" : "local";
26550 						// failed parse. Either no last leaf to fall back to, or there was an explicit
26551 						// zero in the table. Put everything else in the subscriberNumber field as the
26552 						// default place
26553 						if (number.charAt(0) === '^') {
26554 							result = regionSettings.handler[handlerMethod](number.slice(1), i-1, this, regionSettings);
26555 						} else {
26556 							result = regionSettings.handler[handlerMethod](number, i, this, regionSettings);
26557 						}
26558 						break;
26559 					}
26560 				}
26561 			} else if (ch === -1) {
26562 				// non-transition character, continue parsing in the same state
26563 				i++;
26564 			} else {
26565 				// should not happen
26566 				// console.info("skipping character " + ch);
26567 				// not a digit, plus, pound, or star, so this is probably a formatting char. Skip it.
26568 				i++;
26569 			}
26570 		}
26571 		if (i >= number.length && currentState !== regionData.stateData) {
26572 			handlerMethod = (typeof(currentState.l) === 'undefined' || currentState === 0) ? "none" : "local";
26573 			// we reached the end of the phone number, but did not finish recognizing anything. 
26574 			// Default to last resort and put everything that is left into the subscriber number
26575 			//console.log("Reached end of number before parsing was complete. Using handler for method none.")
26576 			if (number.charAt(0) === '^') {
26577 				result = regionSettings.handler[handlerMethod](number.slice(1), i-1, this, regionSettings);
26578 			} else {
26579 				result = regionSettings.handler[handlerMethod](number, i, this, regionSettings);
26580 			}
26581 		}
26582 
26583 		// let the caller know we are done parsing
26584 		if (this.onLoad) {
26585 			this.onLoad(this);
26586 		}
26587 	},
26588 	/**
26589 	 * @protected
26590 	 */
26591 	_getPrefix: function() {
26592 		return this.areaCode || this.serviceCode || this.mobilePrefix || "";
26593 	},
26594 	
26595 	/**
26596 	 * @protected
26597 	 */
26598 	_hasPrefix: function() {
26599 		return (this._getPrefix() !== "");
26600 	},
26601 	
26602 	/**
26603 	 * Exclusive or -- return true, if one is defined and the other isn't
26604 	 * @protected
26605 	 */
26606 	_xor : function(left, right) {
26607 		if ((left === undefined && right === undefined ) || (left !== undefined && right !== undefined)) {
26608 			return false;
26609 		} else {
26610 			return true;
26611 		}
26612 	},
26613 	
26614 	/**
26615 	 * return a version of the phone number that contains only the dialable digits in the correct order 
26616 	 * @protected
26617 	 */
26618 	_join: function () {
26619 		var fieldName, formatted = "";
26620 		
26621 		try {
26622 			for (var field in PhoneNumber._fieldOrder) {
26623 				if (typeof field === 'string' && typeof PhoneNumber._fieldOrder[field] === 'string') {
26624 					fieldName = PhoneNumber._fieldOrder[field];
26625 					// console.info("normalize: formatting field " + fieldName);
26626 					if (this[fieldName] !== undefined) {
26627 						formatted += this[fieldName];
26628 					}
26629 				}
26630 			}
26631 		} catch ( e ) {
26632 			//console.warn("caught exception in _join: " + e);
26633 			throw e;
26634 		}
26635 		return formatted;
26636 	},
26637 
26638 	/**
26639 	 * This routine will compare the two phone numbers in an locale-sensitive
26640 	 * manner to see if they possibly reference the same phone number.<p>
26641 	 * 
26642 	 * In many places,
26643 	 * there are multiple ways to reach the same phone number. In North America for 
26644 	 * example, you might have a number with the trunk access code of "1" and another
26645 	 * without, and they reference the exact same phone number. This is considered a
26646 	 * strong match. For a different pair of numbers, one may be a local number and
26647 	 * the other a full phone number with area code, which may reference the same 
26648 	 * phone number if the local number happens to be located in that area code. 
26649 	 * However, you cannot say for sure if it is in that area code, so it will 
26650 	 * be considered a somewhat weaker match.<p>
26651 	 *  
26652 	 * Similarly, in other countries, there are sometimes different ways of 
26653 	 * reaching the same destination, and the way that numbers
26654 	 * match depends on the locale.<p>
26655 	 * 
26656 	 * The various phone number fields are handled differently for matches. There
26657 	 * are various fields that do not need to match at all. For example, you may
26658 	 * type equally enter "00" or "+" into your phone to start international direct
26659 	 * dialling, so the iddPrefix field does not need to match at all.<p> 
26660 	 * 
26661 	 * Typically, fields that require matches need to match exactly if both sides have a value 
26662 	 * for that field. If both sides specify a value and those values differ, that is
26663 	 * a strong non-match. If one side does not have a value and the other does, that 
26664 	 * causes a partial match, because the number with the missing field may possibly
26665 	 * have an implied value that matches the other number. For example, the numbers
26666 	 * "650-555-1234" and "555-1234" have a partial match as the local number "555-1234"
26667 	 * might possibly have the same 650 area code as the first number, and might possibly
26668 	 * not. If both side do not specify a value for a particular field, that field is 
26669 	 * considered matching.<p>
26670 	 *  
26671 	 * The values of following fields are ignored when performing matches:
26672 	 * 
26673 	 * <ul>
26674 	 * <li>vsc
26675 	 * <li>iddPrefix
26676 	 * <li>cic
26677 	 * <li>trunkAccess
26678 	 * </ul>
26679 	 * 
26680 	 * The values of the following fields matter if they do not match:
26681 	 *   
26682 	 * <ul>
26683 	 * <li>countryCode - A difference causes a moderately strong problem except for 
26684 	 * certain countries where there is a way to access the same subscriber via IDD 
26685 	 * and via intranetwork dialling
26686 	 * <li>mobilePrefix - A difference causes a possible non-match
26687 	 * <li>serviceCode - A difference causes a possible non-match
26688 	 * <li>areaCode - A difference causes a possible non-match
26689 	 * <li>subscriberNumber - A difference causes a very strong non-match
26690 	 * <li>extension - A difference causes a minor non-match
26691 	 * </ul>
26692 	 *  
26693 	 * @param {string|PhoneNumber} other other phone number to compare this one to
26694 	 * @return {number} non-negative integer describing the percentage quality of the 
26695 	 * match. 100 means a very strong match (100%), and lower numbers are less and 
26696 	 * less strong, down to 0 meaning not at all a match. 
26697 	 */
26698 	compare: function (other) {
26699 		var match = 100,
26700 			FRdepartments = {"590":1, "594":1, "596":1, "262":1},
26701 			ITcountries = {"378":1, "379":1},
26702 			thisPrefix,
26703 			otherPrefix,
26704 			currentCountryCode = 0;
26705 
26706 		if (typeof this.locale.region === "string") {
26707 			currentCountryCode = this.locale._mapRegiontoCC(this.locale.region);
26708 		}
26709 		
26710 		// subscriber number must be present and must match
26711 		if (!this.subscriberNumber || !other.subscriberNumber || this.subscriberNumber !== other.subscriberNumber) {
26712 			return 0;
26713 		}
26714 
26715 		// extension must match if it is present
26716 		if (this._xor(this.extension, other.extension) || this.extension !== other.extension) {
26717 			return 0;
26718 		}
26719 
26720 		if (this._xor(this.countryCode, other.countryCode)) {
26721 			// if one doesn't have a country code, give it some demerit points, but if the
26722 			// one that has the country code has something other than the current country
26723 			// add even more. Ignore the special cases where you can dial the same number internationally or via 
26724 			// the local numbering system
26725 			switch (this.locale.getRegion()) {
26726 			case 'FR':
26727 				if (this.countryCode in FRdepartments || other.countryCode in FRdepartments) {
26728 					if (this.areaCode !== other.areaCode || this.mobilePrefix !== other.mobilePrefix) {
26729 						match -= 100;
26730 					}
26731 				} else {
26732 					match -= 16;
26733 				}
26734 				break;
26735 			case 'IT':
26736 				if (this.countryCode in ITcountries || other.countryCode in ITcountries) { 
26737 					if (this.areaCode !== other.areaCode) {
26738 						match -= 100;
26739 					}
26740 				} else {
26741 					match -= 16;
26742 				}
26743 				break;
26744 			default:
26745 				match -= 16;
26746 				if ((this.countryCode !== undefined && this.countryCode !== currentCountryCode) || 
26747 					(other.countryCode !== undefined && other.countryCode !== currentCountryCode)) {
26748 					match -= 16;
26749 				}
26750 			}
26751 		} else if (this.countryCode !== other.countryCode) {
26752 			// ignore the special cases where you can dial the same number internationally or via 
26753 			// the local numbering system
26754 			if (other.countryCode === '33' || this.countryCode === '33') {
26755 				// france
26756 				if (this.countryCode in FRdepartments || other.countryCode in FRdepartments) {
26757 					if (this.areaCode !== other.areaCode || this.mobilePrefix !== other.mobilePrefix) {
26758 						match -= 100;
26759 					}
26760 				} else {
26761 					match -= 100;
26762 				}
26763 			} else if (this.countryCode === '39' || other.countryCode === '39') {
26764 				// italy
26765 				if (this.countryCode in ITcountries || other.countryCode in ITcountries) { 
26766 					if (this.areaCode !== other.areaCode) {
26767 						match -= 100;
26768 					}
26769 				} else {
26770 					match -= 100;
26771 				}
26772 			} else {
26773 				match -= 100;
26774 			}
26775 		}
26776 
26777 		if (this._xor(this.serviceCode, other.serviceCode)) {
26778 			match -= 20;
26779 		} else if (this.serviceCode !== other.serviceCode) {
26780 			match -= 100;
26781 		}
26782 
26783 		if (this._xor(this.mobilePrefix, other.mobilePrefix)) {
26784 			match -= 20;
26785 		} else if (this.mobilePrefix !== other.mobilePrefix) {
26786 			match -= 100;
26787 		}
26788 
26789 		if (this._xor(this.areaCode, other.areaCode)) {
26790 			// one has an area code, the other doesn't, so dock some points. It could be a match if the local
26791 			// number in the one number has the same implied area code as the explicit area code in the other number.
26792 			match -= 12;
26793 		} else if (this.areaCode !== other.areaCode) {
26794 			match -= 100;
26795 		}
26796 
26797 		thisPrefix = this._getPrefix();
26798 		otherPrefix = other._getPrefix();
26799 		
26800 		if (thisPrefix && otherPrefix && thisPrefix !== otherPrefix) {
26801 			match -= 100;
26802 		}
26803 		
26804 		// make sure we are between 0 and 100
26805 		if (match < 0) {
26806 			match = 0;	
26807 		} else if (match > 100) {
26808 			match = 100;
26809 		}
26810 
26811 		return match;
26812 	},
26813 	
26814 	/**
26815 	 * Determine whether or not the other phone number is exactly equal to the current one.<p>
26816 	 *  
26817 	 * The difference between the compare method and the equals method is that the compare 
26818 	 * method compares normalized numbers with each other and returns the degree of match,
26819 	 * whereas the equals operator returns true iff the two numbers contain the same fields
26820 	 * and the fields are exactly the same. Functions and other non-phone number properties
26821 	 * are not compared.
26822 	 * @param {string|PhoneNumber} other another phone number to compare to this one
26823 	 * @return {boolean} true if the numbers are the same, false otherwise
26824 	 */
26825 	equals: function equals(other) {
26826 		if (other.locale && this.locale && !this.locale.equals(other.locale) && (!this.countryCode || !other.countryCode)) {
26827 			return false;
26828 		}
26829 		
26830 		for (var p in other) {
26831 			if (p !== undefined && this[p] !== undefined && typeof(this[p]) !== 'object') {
26832 				if (other[p] === undefined) {
26833 					/*console.error("PhoneNumber.equals: other is missing property " + p + " which has the value " + this[p] + " in this");
26834 					console.error("this is : " + JSON.stringify(this));
26835 					console.error("other is: " + JSON.stringify(other));*/
26836 					return false;
26837 				}
26838 				if (this[p] !== other[p]) {
26839 					/*console.error("PhoneNumber.equals: difference in property " + p);
26840 					console.error("this is : " + JSON.stringify(this));
26841 					console.error("other is: " + JSON.stringify(other));*/
26842 					return false;
26843 				}
26844 			}
26845 		}
26846 		for (var p in other) {
26847 			if (p !== undefined && other[p] !== undefined && typeof(other[p]) !== 'object') {
26848 				if (this[p] === undefined) {
26849 					/*console.error("PhoneNumber.equals: this is missing property " + p + " which has the value " + other[p] + " in the other");
26850 					console.error("this is : " + JSON.stringify(this));
26851 					console.error("other is: " + JSON.stringify(other));*/
26852 					return false;
26853 				}
26854 				if (this[p] !== other[p]) {
26855 					/*console.error("PhoneNumber.equals: difference in property " + p);
26856 					console.error("this is : " + JSON.stringify(this));
26857 					console.error("other is: " + JSON.stringify(other));*/
26858 					return false;
26859 				}
26860 			}
26861 		}
26862 		return true;
26863 	},
26864 	
26865 
26866 	/**
26867 	 * @private
26868 	 * @param {{
26869 	 *   mcc:string,
26870 	 *   defaultAreaCode:string,
26871 	 *   country:string,
26872 	 *   networkType:string,
26873 	 *   assistedDialing:boolean,
26874 	 *   sms:boolean,
26875 	 *   manualDialing:boolean
26876 	 * }} options an object containing options to help in normalizing. 
26877 	 * @param {PhoneNumber} norm
26878 	 * @param {PhoneLocale} homeLocale
26879 	 * @param {PhoneLocale} currentLocale
26880 	 * @param {NumberingPlan} currentPlan
26881 	 * @param {PhoneLocale} destinationLocale
26882 	 * @param {NumberingPlan} destinationPlan
26883 	 * @param {boolean} sync
26884 	 * @param {Object|undefined} loadParams
26885 	 */
26886 	_doNormalize: function(options, norm, homeLocale, currentLocale, currentPlan, destinationLocale, destinationPlan, sync, loadParams) {
26887 		var formatted = "";
26888 		
26889 		if (!norm.invalid && options && options.assistedDialing) {
26890 			// don't normalize things that don't have subscriber numbers. Also, don't normalize
26891 			// manually dialed local numbers. Do normalize local numbers in contact entries.
26892 			if (norm.subscriberNumber && 
26893 					(!options.manualDialing ||
26894 					 norm.iddPrefix ||
26895 					 norm.countryCode ||
26896 					 norm.trunkAccess)) {
26897 				// console.log("normalize: assisted dialling normalization of " + JSON.stringify(norm));
26898 				if (currentLocale.getRegion() !== destinationLocale.getRegion()) {
26899 					// we are currently calling internationally
26900 					if (!norm._hasPrefix() && 
26901 							options.defaultAreaCode && 
26902 							destinationLocale.getRegion() === homeLocale.getRegion() &&
26903 							(!destinationPlan.getFieldLength("minLocalLength") || 
26904 								norm.subscriberNumber.length >= destinationPlan.getFieldLength("minLocalLength"))) {
26905 						// area code is required when dialling from international, but only add it if we are dialing
26906 						// to our home area. Otherwise, the default area code is not valid!
26907 						norm.areaCode = options.defaultAreaCode;
26908 						if (!destinationPlan.getSkipTrunk() && destinationPlan.getTrunkCode()) {
26909 							// some phone systems require the trunk access code, even when dialling from international
26910 							norm.trunkAccess = destinationPlan.getTrunkCode();
26911 						}
26912 					}
26913 					
26914 					if (norm.trunkAccess && destinationPlan.getSkipTrunk()) {
26915 						// on some phone systems, the trunk access code is dropped when dialling from international
26916 						delete norm.trunkAccess;
26917 					}
26918 					
26919 					// make sure to get the country code for the destination region, not the current region!
26920 					if (options.sms) {
26921 						if (homeLocale.getRegion() === "US" && currentLocale.getRegion() !== "US") {
26922 							if (destinationLocale.getRegion() !== "US") {
26923 								norm.iddPrefix = "011"; // non-standard code to make it go through the US first
26924 								norm.countryCode = norm.countryCode || homeLocale._mapRegiontoCC(destinationLocale.getRegion());
26925 							} else if (options.networkType === "cdma") {
26926 								delete norm.iddPrefix;
26927 								delete norm.countryCode;
26928 								if (norm.areaCode) {
26929 									norm.trunkAccess = "1";
26930 								}
26931 							} else if (norm.areaCode) {
26932 								norm.iddPrefix = "+";
26933 								norm.countryCode = "1";
26934 								delete norm.trunkAccess;
26935 							}
26936 						} else {
26937 							norm.iddPrefix = (options.networkType === "cdma") ? currentPlan.getIDDCode() : "+";
26938 							norm.countryCode = norm.countryCode || homeLocale._mapRegiontoCC(destinationLocale.region);
26939 						}
26940 					} else if (norm._hasPrefix() && !norm.countryCode) {
26941 						norm.countryCode = homeLocale._mapRegiontoCC(destinationLocale.region);
26942 					}
26943 
26944 					if (norm.countryCode && !options.sms) {
26945 						// for CDMA, make sure to get the international dialling access code for the current region, not the destination region
26946 						// all umts carriers support plus dialing
26947 						norm.iddPrefix = (options.networkType === "cdma") ? currentPlan.getIDDCode() : "+";
26948 					}
26949 				} else {
26950 					// console.log("normalize: dialing within the country");
26951 					if (options.defaultAreaCode) {
26952 						if (destinationPlan.getPlanStyle() === "open") {
26953 							if (!norm.trunkAccess && norm._hasPrefix() && destinationPlan.getTrunkCode()) {
26954 								// call is not local to this area code, so you have to dial the trunk code and the area code
26955 								norm.trunkAccess = destinationPlan.getTrunkCode();
26956 							}
26957 						} else {
26958 							// In closed plans, you always have to dial the area code, even if the call is local.
26959 							if (!norm._hasPrefix()) {
26960 								if (destinationLocale.getRegion() === homeLocale.getRegion()) {
26961 									norm.areaCode = options.defaultAreaCode;
26962 									if (destinationPlan.getTrunkRequired() && destinationPlan.getTrunkCode()) {
26963 										norm.trunkAccess = norm.trunkAccess || destinationPlan.getTrunkCode();
26964 									}
26965 								}
26966 							} else {
26967 								if (destinationPlan.getTrunkRequired() && destinationPlan.getTrunkCode()) {
26968 									norm.trunkAccess = norm.trunkAccess || destinationPlan.getTrunkCode();
26969 								}
26970 							}
26971 						}
26972 					}
26973 					
26974 					if (options.sms &&
26975 							homeLocale.getRegion() === "US" && 
26976 							currentLocale.getRegion() !== "US") {
26977 						norm.iddPrefix = "011"; // make it go through the US first
26978 						if (destinationPlan.getSkipTrunk() && norm.trunkAccess) {
26979 							delete norm.trunkAccess;
26980 						}
26981 					} else if (norm.iddPrefix || norm.countryCode) {
26982 						// we are in our destination country, so strip the international dialling prefixes
26983 						delete norm.iddPrefix;
26984 						delete norm.countryCode;
26985 						
26986 						if ((destinationPlan.getPlanStyle() === "open" || destinationPlan.getTrunkRequired()) && destinationPlan.getTrunkCode()) {
26987 							norm.trunkAccess = destinationPlan.getTrunkCode();
26988 						}
26989 					}
26990 				}
26991 			}
26992 		} else if (!norm.invalid) {
26993 			// console.log("normalize: non-assisted normalization");
26994 			if (!norm._hasPrefix() && options && options.defaultAreaCode && destinationLocale.getRegion() === homeLocale.region) {
26995 				norm.areaCode = options.defaultAreaCode;
26996 			}
26997 			
26998 			if (!norm.countryCode && norm._hasPrefix()) {
26999 				norm.countryCode = homeLocale._mapRegiontoCC(destinationLocale.getRegion());
27000 			}
27001 
27002 			if (norm.countryCode) {
27003 				if (options && options.networkType && options.networkType === "cdma") {
27004 					norm.iddPrefix = currentPlan.getIDDCode(); 
27005 				} else {
27006 					// all umts carriers support plus dialing
27007 					norm.iddPrefix = "+";
27008 				}
27009 		
27010 				if (destinationPlan.getSkipTrunk() && norm.trunkAccess) {
27011 					delete norm.trunkAccess;
27012 				} else if (!destinationPlan.getSkipTrunk() && !norm.trunkAccess && destinationPlan.getTrunkCode()) {
27013 					norm.trunkAccess = destinationPlan.getTrunkCode();
27014 				}
27015 			}
27016 		}
27017 		
27018 		// console.info("normalize: after normalization, the normalized phone number is: " + JSON.stringify(norm));
27019 		formatted = norm._join();
27020 
27021 		return formatted;
27022 	},
27023 	
27024 	/**
27025 	 * @private
27026 	 * @param {{
27027 	 *   mcc:string,
27028 	 *   defaultAreaCode:string,
27029 	 *   country:string,
27030 	 *   networkType:string,
27031 	 *   assistedDialing:boolean,
27032 	 *   sms:boolean,
27033 	 *   manualDialing:boolean
27034 	 * }} options an object containing options to help in normalizing. 
27035 	 * @param {PhoneNumber} norm
27036 	 * @param {PhoneLocale} homeLocale
27037 	 * @param {PhoneLocale} currentLocale
27038 	 * @param {NumberingPlan} currentPlan
27039 	 * @param {PhoneLocale} destinationLocale
27040 	 * @param {NumberingPlan} destinationPlan
27041 	 * @param {boolean} sync
27042 	 * @param {Object|undefined} loadParams
27043 	 * @param {function(string)} callback
27044 	 */
27045 	_doReparse: function(options, norm, homeLocale, currentLocale, currentPlan, destinationLocale, destinationPlan, sync, loadParams, callback) {
27046 		var formatted, 
27047 			tempRegion;
27048 		
27049 		if (options &&
27050 				options.assistedDialing &&
27051 				!norm.trunkAccess && 
27052 				!norm.iddPrefix &&
27053 				norm.subscriberNumber && 
27054 				norm.subscriberNumber.length > destinationPlan.getFieldLength("maxLocalLength")) {
27055 
27056 			// numbers that are too long are sometimes international direct dialed numbers that
27057 			// are missing the IDD prefix. So, try reparsing it using a plus in front to see if that works.
27058 			new PhoneNumber("+" + this._join(), {
27059 				locale: this.locale,
27060 				sync: sync,
27061 				loadParms: loadParams,
27062 				onLoad: ilib.bind(this, function (data) {
27063 					tempRegion = (data.countryCode && data.locale._mapCCtoRegion(data.countryCode));
27064 
27065 					if (tempRegion && tempRegion !== "unknown" && tempRegion !== "SG") {
27066 						// only use it if it is a recognized country code. Singapore (SG) is a special case.
27067 						norm = data;
27068 						destinationLocale = data.destinationLocale;
27069 						destinationPlan = data.destinationPlan;
27070 					}
27071 					
27072 					formatted = this._doNormalize(options, norm, homeLocale, currentLocale, currentPlan, destinationLocale, destinationPlan, sync, loadParams);
27073 					if (typeof(callback) === 'function') {
27074 						callback(formatted);
27075 					}
27076 				})
27077 			});
27078 		} else if (options && options.assistedDialing && norm.invalid && currentLocale.region !== norm.locale.region) {
27079 			// if this number is not valid for the locale it was parsed with, try again with the current locale
27080 			// console.log("norm is invalid. Attempting to reparse with the current locale");
27081 
27082 			new PhoneNumber(this._join(), {
27083 				locale: currentLocale,
27084 				sync: sync,
27085 				loadParms: loadParams,
27086 				onLoad: ilib.bind(this, function (data) {
27087 					if (data && !data.invalid) {
27088 						norm = data;
27089 					}
27090 					
27091 					formatted = this._doNormalize(options, norm, homeLocale, currentLocale, currentPlan, destinationLocale, destinationPlan, sync, loadParams);
27092 					if (typeof(callback) === 'function') {
27093 						callback(formatted);
27094 					}
27095 				})
27096 			});
27097 		} else {
27098 			formatted = this._doNormalize(options, norm, homeLocale, currentLocale, currentPlan, destinationLocale, destinationPlan, sync, loadParams);
27099 			if (typeof(callback) === 'function') {
27100 				callback(formatted);
27101 			}
27102 		}
27103 	},
27104 	
27105 	/**
27106 	 * This function normalizes the current phone number to a canonical format and returns a
27107 	 * string with that phone number. If parts are missing, this function attempts to fill in 
27108 	 * those parts.<p>
27109 	 * 	  
27110 	 * The options object contains a set of properties that can possibly help normalize
27111 	 * this number by providing "extra" information to the algorithm. The options
27112 	 * parameter may be null or an empty object if no hints can be determined before
27113 	 * this call is made. If any particular hint is not
27114 	 * available, it does not need to be present in the options object.<p>
27115 	 * 
27116 	 * The following is a list of hints that the algorithm will look for in the options
27117 	 * object:
27118 	 * 
27119 	 * <ul>
27120 	 * <li><i>mcc</i> the mobile carrier code of the current network upon which this 
27121 	 * phone is operating. This is translated into an IDD country code. This is 
27122 	 * useful if the number being normalized comes from CNAP (callerid) and the
27123 	 * MCC is known.
27124 	 * <li><i>defaultAreaCode</i> the area code of the phone number of the current
27125 	 * device, if available. Local numbers in a person's contact list are most 
27126 	 * probably in this same area code.
27127 	 * <li><i>country</i> the 2 letter ISO 3166 code of the country if it is
27128 	 * known from some other means such as parsing the physical address of the
27129 	 * person associated with the phone number, or the from the domain name 
27130 	 * of the person's email address
27131 	 * <li><i>networkType</i> specifies whether the phone is currently connected to a
27132 	 * CDMA network or a UMTS network. Valid values are the strings "cdma" and "umts".
27133 	 * If one of those two strings are not specified, or if this property is left off
27134 	 * completely, this method will assume UMTS.
27135 	 * </ul>
27136 	 * 
27137 	 * The following are a list of options that control the behaviour of the normalization:
27138 	 * 
27139 	 * <ul>
27140 	 * <li><i>assistedDialing</i> if this is set to true, the number will be normalized
27141 	 * so that it can dialled directly on the type of network this phone is 
27142 	 * currently connected to. This allows customers to dial numbers or use numbers 
27143 	 * in their contact list that are specific to their "home" region when they are 
27144 	 * roaming and those numbers would not otherwise work with the current roaming 
27145 	 * carrier as they are. The home region is 
27146 	 * specified as the phoneRegion system preference that is settable in the 
27147 	 * regional settings app. With assisted dialling, this method will add or 
27148 	 * remove international direct dialling prefixes and country codes, as well as
27149 	 * national trunk access codes, as required by the current roaming carrier and the
27150 	 * home region in order to dial the number properly. If it is not possible to 
27151 	 * construct a full international dialling sequence from the options and hints given,
27152 	 * this function will not modify the phone number, and will return "undefined".
27153 	 * If assisted dialling is false or not specified, then this method will attempt
27154 	 * to add all the information it can to the number so that it is as fully
27155 	 * specified as possible. This allows two numbers to be compared more easily when
27156 	 * those two numbers were otherwise only partially specified.
27157 	 * <li><i>sms</i> set this option to true for the following conditions: 
27158 	 *   <ul>
27159 	 *   <li>assisted dialing is turned on
27160 	 *   <li>the phone number represents the destination of an SMS message
27161 	 *   <li>the phone is UMTS 
27162 	 *   <li>the phone is SIM-locked to its carrier
27163 	 *   </ul> 
27164 	 * This enables special international direct dialling codes to route the SMS message to
27165 	 * the correct carrier. If assisted dialling is not turned on, this option has no
27166 	 * affect.
27167 	 * <li><i>manualDialing</i> set this option to true if the user is entering this number on
27168 	 * the keypad directly, and false when the number comes from a stored location like a 
27169 	 * contact entry or a call log entry. When true, this option causes the normalizer to 
27170 	 * not perform any normalization on numbers that look like local numbers in the home 
27171 	 * country. If false, all numbers go through normalization. This option only has an effect
27172 	 * when the assistedDialing option is true as well, otherwise it is ignored.
27173 	 * </ul> 
27174 	 * 
27175 	 * If both a set of options and a locale are given, and they offer conflicting
27176 	 * information, the options will take precedence. The idea is that the locale
27177 	 * tells you the region setting that the user has chosen (probably in 
27178 	 * firstuse), whereas the the hints are more current information such as
27179 	 * where the phone is currently operating (the MCC).<p> 
27180 	 * 
27181 	 * This function performs the following types of normalizations with assisted
27182 	 * dialling turned on:
27183 	 * 
27184 	 * <ol>
27185 	 * <li>If the current location of the phone matches the home country, this is a
27186 	 * domestic call.
27187 	 *   <ul> 
27188 	 *   <li>Remove any iddPrefix and countryCode fields, as they are not needed
27189 	 *   <li>Add in a trunkAccess field that may be necessary to call a domestic numbers 
27190 	 *     in the home country
27191 	 *   </ul>
27192 	 * <li> If the current location of the phone does not match the home country,
27193 	 * attempt to form a whole international number.
27194 	 *   <ul>
27195 	 *   <li>Add in the area code if it is missing from the phone number and the area code
27196 	 *     of the current phone is available in the hints
27197 	 *   <li>Add the country dialling code for the home country if it is missing from the 
27198 	 *     phone number
27199 	 *   <li>Add or replace the iddPrefix with the correct one for the current country. The
27200 	 *     phone number will have been parsed with the settings for the home country, so
27201 	 *     the iddPrefix may be incorrect for the
27202 	 *     current country. The iddPrefix for the current country can be "+" if the phone 
27203 	 *     is connected to a UMTS network, and either a "+" or a country-dependent 
27204 	 *     sequences of digits for CDMA networks.
27205 	 *   </ul>
27206 	 * </ol>
27207 	 * 
27208 	 * This function performs the following types of normalization with assisted
27209 	 * dialling turned off:
27210 	 * 
27211 	 * <ul>
27212 	 * <li>Normalize the international direct dialing prefix to be a plus or the
27213 	 * international direct dialling access code for the current country, depending
27214 	 * on the network type.
27215 	 * <li>If a number is a local number (ie. it is missing its area code), 
27216 	 * use a default area code from the hints if available. CDMA phones always know their area 
27217 	 * code, and GSM/UMTS phones know their area code in many instances, but not always 
27218 	 * (ie. not on Vodaphone or Telcel phones). If the default area code is not available, 
27219 	 * do not add it.
27220 	 * <li>In assisted dialling mode, if a number is missing its country code, 
27221 	 * use the current MCC number if
27222 	 * it is available to figure out the current country code, and prepend that 
27223 	 * to the number. If it is not available, leave it off. Also, use that 
27224 	 * country's settings to parse the number instead of the current format 
27225 	 * locale.
27226 	 * <li>For North American numbers with an area code but no trunk access 
27227 	 * code, add in the trunk access code.
27228 	 * <li>For other countries, if the country code is added in step 3, remove the 
27229 	 * trunk access code when required by that country's conventions for 
27230 	 * international calls. If the country requires a trunk access code for 
27231 	 * international calls and it doesn't exist, add one.
27232 	 * </ul>
27233 	 *  
27234 	 * This method modifies the current object, and also returns a string 
27235 	 * containing the normalized phone number that can be compared directly against
27236 	 * other normalized numbers. The canonical format for phone numbers that is 
27237 	 * returned from thhomeLocaleis method is simply an uninterrupted and unformatted string 
27238 	 * of dialable digits.
27239 	 * 
27240 	 * @param {{
27241 	 *   mcc:string,
27242 	 *   defaultAreaCode:string,
27243 	 *   country:string,
27244 	 *   networkType:string,
27245 	 *   assistedDialing:boolean,
27246 	 *   sms:boolean,
27247 	 *   manualDialing:boolean
27248 	 * }} options an object containing options to help in normalizing. 
27249 	 * @return {string|undefined} the normalized string, or undefined if the number
27250 	 * could not be normalized
27251 	 */
27252 	normalize: function(options) {
27253 		var norm,
27254 			sync = true,
27255 			loadParams = {};
27256 			
27257 
27258 		if (options) {
27259 			if (typeof(options.sync) !== 'undefined') {
27260 				sync = (options.sync == true);
27261 			}
27262 			
27263 			if (options.loadParams) {
27264 				loadParams = options.loadParams;
27265 			}
27266 		}
27267 		
27268 		// Clone this number, so we don't mess with the original.
27269 		// No need to do this asynchronously because it's a copy constructor which doesn't 
27270 		// load any extra files.
27271 		norm = new PhoneNumber(this);
27272 
27273 		var normalized;
27274 		
27275 		if (options && (typeof(options.mcc) !== 'undefined' || typeof(options.country) !== 'undefined')) {
27276 			new PhoneLocale({
27277 				mcc: options.mcc,
27278 				countryCode: options.countryCode,
27279 				locale: this.locale,
27280 				sync: sync,
27281 				loadParams: loadParams,
27282 				onLoad: ilib.bind(this, function(loc) {
27283 					new NumberingPlan({
27284 						locale: loc,
27285 						sync: sync,
27286 						loadParms: loadParams,
27287 						onLoad: ilib.bind(this, function (plan) {
27288 							this._doReparse(options, norm, this.locale, loc, plan, this.destinationLocale, this.destinationPlan, sync, loadParams, function (fmt) {
27289 								normalized = fmt;
27290 								
27291 								if (options && typeof(options.onLoad) === 'function') {
27292 									options.onLoad(fmt);
27293 								}
27294 							});
27295 						})
27296 					});
27297 				})
27298 			});
27299 		} else {
27300 			this._doReparse(options, norm, this.locale, this.locale, this.plan, this.destinationLocale, this.destinationPlan, sync, loadParams, function (fmt) {
27301 				normalized = fmt;
27302 				
27303 				if (options && typeof(options.onLoad) === 'function') {
27304 					options.onLoad(fmt);
27305 				}
27306 			});
27307 		}
27308 
27309 		// return the value for the synchronous case
27310 		return normalized;
27311 	}
27312 };
27313 
27314 
27315 /*< PhoneFmt.js */
27316 /*
27317  * phonefmt.js - Represent a phone number formatter.
27318  * 
27319  * Copyright © 2014-2015, JEDLSoft
27320  *
27321  * Licensed under the Apache License, Version 2.0 (the "License");
27322  * you may not use this file except in compliance with the License.
27323  * You may obtain a copy of the License at
27324  *
27325  *     http://www.apache.org/licenses/LICENSE-2.0
27326  *
27327  * Unless required by applicable law or agreed to in writing, software
27328  * distributed under the License is distributed on an "AS IS" BASIS,
27329  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
27330  *
27331  * See the License for the specific language governing permissions and
27332  * limitations under the License.
27333  */
27334 
27335 /*
27336 !depends 
27337 ilib.js 
27338 Locale.js 
27339 NumberingPlan.js
27340 PhoneNumber.js
27341 PhoneLocale.js
27342 Utils.js
27343 JSUtils.js
27344 */
27345 
27346 // !data phonefmt
27347 
27348 
27349 /**
27350  * @class
27351  * Create a new phone number formatter object that formats numbers according to the parameters.<p>
27352  * 
27353  * The options object can contain zero or more of the following parameters:
27354  *
27355  * <ul>
27356  * <li><i>locale</i> locale to use to format this number, or undefined to use the default locale
27357  * <li><i>style</i> the name of style to use to format numbers, or undefined to use the default style
27358  * <li><i>mcc</i> the MCC of the country to use if the number is a local number and the country code is not known
27359  *
27360  * <li><i>onLoad</i> - a callback function to call when the locale data is fully loaded and the address has been 
27361  * parsed. When the onLoad option is given, the address formatter object 
27362  * will attempt to load any missing locale data using the ilib loader callback.
27363  * When the constructor is done (even if the data is already preassembled), the 
27364  * onLoad function is called with the current instance as a parameter, so this
27365  * callback can be used with preassembled or dynamic loading or a mix of the two. 
27366  * 
27367  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
27368  * asynchronously. If this option is given as "false", then the "onLoad"
27369  * callback must be given, as the instance returned from this constructor will
27370  * not be usable for a while. 
27371  *
27372  * <li><i>loadParams</i> - an object containing parameters to pass to the 
27373  * loader callback function when locale data is missing. The parameters are not
27374  * interpretted or modified in any way. They are simply passed along. The object 
27375  * may contain any property/value pairs as long as the calling code is in
27376  * agreement with the loader callback function as to what those parameters mean.
27377  * </ul>
27378  *
27379  * Some regions have more than one style of formatting, and the style parameter
27380  * selects which style the user prefers. An array of style names that this locale
27381  * supports can be found by calling {@link PhoneFmt.getAvailableStyles}. 
27382  * Example phone numbers can be retrieved for each style by calling 
27383  * {@link PhoneFmt.getStyleExample}.
27384  * <p>
27385  *
27386  * If the MCC is given, numbers will be formatted in the manner of the country
27387  * specified by the MCC. If it is not given, but the locale is, the manner of
27388  * the country in the locale will be used. If neither the locale or MCC are not given,
27389  * then the country of the current ilib locale is used. 
27390  *
27391  * @constructor
27392  * @param {Object} options properties that control how this formatter behaves
27393  */
27394 var PhoneFmt = function(options) {
27395 	this.sync = true;
27396 	this.styleName = 'default',
27397 	this.loadParams = {};
27398 
27399 	var locale = new Locale();
27400 
27401 	if (options) {
27402 		if (options.locale) {
27403 			locale = options.locale;
27404 		}
27405 
27406 		if (typeof(options.sync) !== 'undefined') {
27407 			this.sync = (options.sync == true);
27408 		}
27409 
27410 		if (options.loadParams) {
27411 			this.loadParams = options.loadParams;
27412 		}
27413 
27414 		if (options.style) {
27415 			this.style = options.style;
27416 		}
27417 	}
27418 
27419 	new PhoneLocale({
27420 		locale: locale,
27421 		mcc: options && options.mcc,
27422 		countryCode: options && options.countryCode,
27423 		onLoad: ilib.bind(this, function (data) {
27424 			/** @type {PhoneLocale} */
27425 			this.locale = data;
27426 
27427 			new NumberingPlan({
27428 				locale: this.locale,
27429 				sync: this.sync,
27430 				loadParms: this.loadParams,
27431 				onLoad: ilib.bind(this, function (plan) {
27432 					/** @type {NumberingPlan} */
27433 					this.plan = plan;
27434 
27435 					Utils.loadData({
27436 						name: "phonefmt.json",
27437 						object: PhoneFmt,
27438 						locale: this.locale, 
27439 						sync: this.sync,
27440 						loadParams: JSUtils.merge(this.loadParams, {
27441 							returnOne: true
27442 						}),
27443 						callback: ilib.bind(this, function (fmtdata) {
27444 							this.fmtdata = fmtdata;
27445 							
27446 							if (options && typeof(options.onLoad) === 'function') {
27447 								options.onLoad(this);
27448 							}
27449 						})
27450 					});
27451 				})
27452 			});
27453 		})
27454 	});
27455 };
27456 
27457 PhoneFmt.prototype = {
27458 	/**
27459 	 * 
27460 	 * @protected
27461 	 * @param {string} part
27462 	 * @param {Object} formats
27463 	 * @param {boolean} mustUseAll
27464 	 */
27465 	_substituteDigits: function(part, formats, mustUseAll) {
27466 		var formatString,
27467 			formatted = "",
27468 			partIndex = 0,
27469 			templates,
27470 			i;
27471 
27472 		// console.info("Globalization.Phone._substituteDigits: typeof(formats) is " + typeof(formats));
27473 		if (!part) {
27474 			return formatted;
27475 		}
27476 
27477 		if (typeof(formats) === "object") {
27478 			templates = (typeof(formats.template) !== 'undefined') ? formats.template : formats;
27479 			if (part.length > templates.length) {
27480 				// too big, so just use last resort rule.
27481 				throw "part " + part + " is too big. We do not have a format template to format it.";
27482 			}
27483 			// use the format in this array that corresponds to the digit length of this
27484 			// part of the phone number
27485 			formatString =  templates[part.length-1];
27486 			// console.info("Globalization.Phone._substituteDigits: formats is an Array: " + JSON.stringify(formats));
27487 		} else {
27488 			formatString = formats;
27489 		}
27490 
27491 		for (i = 0; i < formatString.length; i++) {
27492 			if (formatString.charAt(i) === "X") {
27493 				formatted += part.charAt(partIndex);
27494 				partIndex++;
27495 			} else {
27496 				formatted += formatString.charAt(i);
27497 			}
27498 		}
27499 		
27500 		if (mustUseAll && partIndex < part.length-1) {
27501 			// didn't use the whole thing in this format? Hmm... go to last resort rule
27502 			throw "too many digits in " + part + " for format " + formatString;
27503 		}
27504 		
27505 		return formatted;
27506 	},
27507 	
27508 	/**
27509 	 * Returns the style with the given name, or the default style if there
27510 	 * is no style with that name.
27511 	 * @protected
27512 	 * @return {{example:string,whole:Object.<string,string>,partial:Object.<string,string>}|Object.<string,string>}
27513 	 */
27514 	_getStyle: function (name, fmtdata) {
27515 		return fmtdata[name] || fmtdata["default"];
27516 	},
27517 
27518 	/**
27519 	 * Do the actual work of formatting the phone number starting at the given
27520 	 * field in the regular field order.
27521 	 * 
27522 	 * @param {!PhoneNumber} number
27523 	 * @param {{
27524 	 *   partial:boolean,
27525 	 *   style:string,
27526 	 *   mcc:string,
27527 	 *   locale:(string|Locale),
27528 	 *   sync:boolean,
27529 	 *   loadParams:Object,
27530 	 *   onLoad:function(string)
27531 	 * }} options Parameters which control how to format the number
27532 	 * @param {number} startField
27533 	 */
27534 	_doFormat: function(number, options, startField, locale, fmtdata, callback) {
27535 		var sync = true,
27536 			loadParams = {},
27537 			temp, 
27538 			templates, 
27539 			fieldName, 
27540 			countryCode, 
27541 			isWhole, 
27542 			style,
27543 			formatted = "",
27544 			styleTemplates,
27545 			lastFieldName;
27546 	
27547 		if (options) {
27548 			if (typeof(options.sync) !== 'undefined') {
27549 				sync = (options.sync == true);				
27550 			}
27551 		
27552 			if (options.loadParams) {
27553 				loadParams = options.loadParams;
27554 			}
27555 		}
27556 	
27557 		style = this.style; // default style for this formatter
27558 
27559 		// figure out what style to use for this type of number
27560 		if (number.countryCode) {
27561 			// dialing from outside the country
27562 			// check to see if it to a mobile number because they are often formatted differently
27563 			style = (number.mobilePrefix) ? "internationalmobile" : "international";
27564 		} else if (number.mobilePrefix !== undefined) {
27565 			style = "mobile";
27566 		} else if (number.serviceCode !== undefined && typeof(fmtdata["service"]) !== 'undefined') {
27567 			// if there is a special format for service numbers, then use it
27568 			style = "service";
27569 		}
27570 
27571 		isWhole = (!options || !options.partial);
27572 		styleTemplates = this._getStyle(style, fmtdata);
27573 		
27574 		// console.log("Style ends up being " + style + " and using subtype " + (isWhole ? "whole" : "partial"));
27575 		styleTemplates = (isWhole ? styleTemplates.whole : styleTemplates.partial) || styleTemplates;
27576 
27577 		for (var i = startField; i < PhoneNumber._fieldOrder.length; i++) {
27578 			fieldName = PhoneNumber._fieldOrder[i];
27579 			// console.info("format: formatting field " + fieldName + " value: " + number[fieldName]);
27580 			if (number[fieldName] !== undefined) {
27581 				if (styleTemplates[fieldName] !== undefined) {
27582 					templates = styleTemplates[fieldName];
27583 					if (fieldName === "trunkAccess") {
27584 						if (number.areaCode === undefined && number.serviceCode === undefined && number.mobilePrefix === undefined) {
27585 							templates = "X";
27586 						}
27587 					}
27588 					if (lastFieldName && typeof(styleTemplates[lastFieldName].suffix) !== 'undefined') {
27589 						if (fieldName !== "extension" && number[fieldName].search(/[xwtp,;]/i) <= -1) {
27590 							formatted += styleTemplates[lastFieldName].suffix;	
27591 						}
27592 					}
27593 					lastFieldName = fieldName;
27594 					
27595 					// console.info("format: formatting field " + fieldName + " with templates " + JSON.stringify(templates));
27596 					temp = this._substituteDigits(number[fieldName], templates, (fieldName === "subscriberNumber"));
27597 					// console.info("format: formatted is: " + temp);
27598 					formatted += temp;
27599 	
27600 					if (fieldName === "countryCode") {
27601 						// switch to the new country to format the rest of the number
27602 						countryCode = number.countryCode.replace(/[wWpPtT\+#\*]/g, '');	// fix for NOV-108200
27603 
27604 						new PhoneLocale({
27605 							locale: this.locale,
27606 							sync: sync,							
27607 							loadParms: loadParams,
27608 							countryCode: countryCode,
27609 							onLoad: ilib.bind(this, function (locale) {
27610 								Utils.loadData({
27611 									name: "phonefmt.json",
27612 									object: PhoneFmt,
27613 									locale: locale,
27614 									sync: sync,
27615 									loadParams: JSUtils.merge(loadParams, {
27616 										returnOne: true
27617 									}),
27618 									callback: ilib.bind(this, function (fmtdata) {
27619 										// console.info("format: switching to region " + locale.region + " and style " + style + " to format the rest of the number ");
27620 										
27621 										var subfmt = "";
27622 
27623 										this._doFormat(number, options, i+1, locale, fmtdata, function (subformat) {
27624 											subfmt = subformat;
27625 											if (typeof(callback) === 'function') {
27626 												callback(formatted + subformat);
27627 											}
27628 										});
27629 										
27630 										formatted += subfmt;
27631 									})
27632 								});
27633 							})
27634 						});
27635 						return formatted;
27636 					}
27637 				} else {
27638 					//console.warn("PhoneFmt.format: cannot find format template for field " + fieldName + ", region " + locale.region + ", style " + style);
27639 					// use default of "minimal formatting" so we don't miss parts because of bugs in the format templates
27640 					formatted += number[fieldName];
27641 				}
27642 			}
27643 		}
27644 		
27645 		if (typeof(callback) === 'function') {
27646 			callback(formatted);
27647 		}
27648 
27649 		return formatted;
27650 	},
27651 	
27652 	/**
27653 	 * Format the parts of a phone number appropriately according to the settings in 
27654 	 * this formatter instance.
27655 	 *  
27656 	 * The options can contain zero or more of these properties:
27657 	 * 
27658 	 * <ul>
27659 	 * <li><i>partial</i> boolean which tells whether or not this phone number 
27660 	 * represents a partial number or not. The default is false, which means the number 
27661 	 * represents a whole number. 
27662 	 * <li><i>style</i> style to use to format the number, if different from the 
27663 	 * default style or the style specified in the constructor
27664 	 * <li><i>locale</i> The locale with which to parse the number. This gives a clue as to which
27665      * numbering plan to use.
27666      * <li><i>mcc</i> The mobile carrier code (MCC) associated with the carrier that the phone is 
27667      * currently connected to, if known. This also can give a clue as to which numbering plan to
27668      * use
27669      * <li><i>onLoad</i> - a callback function to call when the date format object is fully 
27670      * loaded. When the onLoad option is given, the DateFmt object will attempt to
27671      * load any missing locale data using the ilib loader callback.
27672      * When the constructor is done (even if the data is already preassembled), the 
27673      * onLoad function is called with the current instance as a parameter, so this
27674      * callback can be used with preassembled or dynamic loading or a mix of the two.
27675      * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
27676      * asynchronously. If this option is given as "false", then the "onLoad"
27677      * callback must be given, as the instance returned from this constructor will
27678      * not be usable for a while.
27679      * <li><i>loadParams</i> - an object containing parameters to pass to the 
27680      * loader callback function when locale data is missing. The parameters are not
27681      * interpretted or modified in any way. They are simply passed along. The object 
27682      * may contain any property/value pairs as long as the calling code is in
27683      * agreement with the loader callback function as to what those parameters mean.
27684 	 * </ul>
27685 	 *      
27686 	 * The partial parameter specifies whether or not the phone number contains
27687 	 * a partial phone number or if it is a whole phone number. A partial 
27688 	 * number is usually a number as the user is entering it with a dial pad. The
27689 	 * reason is that certain types of phone numbers should be formatted differently
27690 	 * depending on whether or not it represents a whole number. Specifically, SMS
27691 	 * short codes are formatted differently.<p>
27692 	 * 
27693 	 * Example: a subscriber number of "48773" in the US would get formatted as:
27694 	 * 
27695 	 * <ul>
27696 	 * <li>partial: 487-73  (perhaps the user is in the process of typing a whole phone 
27697 	 * number such as 487-7379)
27698 	 * <li>whole:   48773   (this is the entire SMS short code)
27699 	 * </ul>
27700 	 * 
27701 	 * Any place in the UI where the user types in phone numbers, such as the keypad in 
27702 	 * the phone app, should pass in partial: true to this formatting routine. All other 
27703 	 * places, such as the call log in the phone app, should pass in partial: false, or 
27704 	 * leave the partial flag out of the parameters entirely. 
27705 	 * 
27706 	 * @param {!PhoneNumber} number object containing the phone number to format
27707 	 * @param {{
27708 	 *   partial:boolean,
27709 	 *   style:string,
27710 	 *   mcc:string,
27711 	 *   locale:(string|Locale),
27712 	 *   sync:boolean,
27713 	 *   loadParams:Object,
27714 	 *   onLoad:function(string)
27715 	 * }} options Parameters which control how to format the number
27716 	 * @return {string} Returns the formatted phone number as a string.
27717 	 */
27718 	format: function (number, options) {
27719 		var formatted = "",
27720 		    callback;
27721 
27722 		callback = options && options.onLoad;
27723 
27724 		try {
27725 			this._doFormat(number, options, 0, this.locale, this.fmtdata, function (fmt) {
27726 				formatted = fmt;
27727 				
27728 				if (typeof(callback) === 'function') {
27729 					callback(fmt);
27730 				}
27731 			});
27732 		} catch (e) {
27733 			if (typeof(e) === 'string') { 
27734 				// console.warn("caught exception: " + e + ". Using last resort rule.");
27735 				// if there was some exception, use this last resort rule
27736 				formatted = "";
27737 				for (var field in PhoneNumber._fieldOrder) {
27738 					if (typeof field === 'string' && typeof PhoneNumber._fieldOrder[field] === 'string' && number[PhoneNumber._fieldOrder[field]] !== undefined) {
27739 						// just concatenate without any formatting
27740 						formatted += number[PhoneNumber._fieldOrder[field]];
27741 						if (PhoneNumber._fieldOrder[field] === 'countryCode') {
27742 							formatted += ' ';		// fix for NOV-107894
27743 						}
27744 					}
27745 				}
27746 			} else {
27747 				throw e;
27748 			}
27749 			
27750 			if (typeof(callback) === 'function') {
27751 				callback(formatted);
27752 			}
27753 		}
27754 		return formatted;
27755 	},
27756 	
27757 	/**
27758 	 * Return an array of names of all available styles that can be used with the current 
27759 	 * formatter.
27760 	 * @return {Array.<string>} an array of names of styles that are supported by this formatter
27761 	 */
27762 	getAvailableStyles: function () {
27763 		var ret = [],
27764 			style;
27765 
27766 		if (this.fmtdata) {
27767 			for (style in this.fmtdata) {
27768 				if (this.fmtdata[style].example) {
27769 					ret.push(style);
27770 				}
27771 			}
27772 		}
27773 		return ret;
27774 	},
27775 	
27776 	/**
27777 	 * Return an example phone number formatted with the given style.
27778 	 * 
27779 	 * @param {string|undefined} style style to get an example of, or undefined to use
27780 	 * the current default style for this formatter
27781 	 * @return {string|undefined} an example phone number formatted according to the 
27782 	 * given style, or undefined if the style is not recognized or does not have an 
27783 	 * example 
27784 	 */
27785 	getStyleExample: function (style) {
27786 		return this.fmtdata[style].example || undefined;
27787 	}
27788 };
27789 
27790 
27791 /*< PhoneGeoLocator.js */
27792 /*
27793  * phonegeo.js - Represent a phone number geolocator object.
27794  * 
27795  * Copyright © 2014-2015, JEDLSoft
27796  *
27797  * Licensed under the Apache License, Version 2.0 (the "License");
27798  * you may not use this file except in compliance with the License.
27799  * You may obtain a copy of the License at
27800  *
27801  *     http://www.apache.org/licenses/LICENSE-2.0
27802  *
27803  * Unless required by applicable law or agreed to in writing, software
27804  * distributed under the License is distributed on an "AS IS" BASIS,
27805  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
27806  *
27807  * See the License for the specific language governing permissions and
27808  * limitations under the License.
27809  */
27810 
27811 /*
27812 !depends 
27813 ilib.js 
27814 NumberingPlan.js
27815 PhoneLocale.js
27816 PhoneNumber.js
27817 Utils.js
27818 JSUtils.js
27819 ResBundle.js
27820 */
27821 
27822 // !data iddarea area extarea extstates phoneres
27823 
27824 
27825 
27826 /**
27827  * @class
27828  * Create an instance that can geographically locate a phone number.<p>
27829  * 
27830  * The location of the number is calculated according to the following rules:
27831  * 
27832  * <ol>
27833  * <li>If the areaCode property is undefined or empty, or if the number specifies a 
27834  * country code for which we do not have information, then the area property may be 
27835  * missing from the returned object. In this case, only the country object will be returned.
27836  * 
27837  * <li>If there is no area code, but there is a mobile prefix, service code, or emergency 
27838  * code, then a fixed string indicating the type of number will be returned.
27839  * 
27840  * <li>The country object is filled out according to the countryCode property of the phone
27841  * number. 
27842  * 
27843  * <li>If the phone number does not have an explicit country code, the MCC will be used if
27844  * it is available. The country code can be gleaned directly from the MCC. If the MCC 
27845  * of the carrier to which the phone is currently connected is available, it should be 
27846  * passed in so that local phone numbers will look correct.
27847  * 
27848  * <li>If the country's dialling plan mandates a fixed length for phone numbers, and a 
27849  * particular number exceeds that length, then the area code will not be given on the
27850  * assumption that the number has problems in the first place and we cannot guess
27851  * correctly.
27852  * </ol>
27853  * 
27854  * The returned area property varies in specificity according
27855  * to the locale. In North America, the area is no finer than large parts of states
27856  * or provinces. In Germany and the UK, the area can be as fine as small towns.<p>
27857  * 
27858  * If the number passed in is invalid, no geolocation will be performed. If the location
27859  * information about the country where the phone number is located is not available,
27860  * then the area information will be missing and only the country will be available.<p>
27861  * 
27862  * The options parameter can contain any one of the following properties:
27863  * 
27864  * <ul>
27865  * <li><i>locale</i> The locale parameter is used to load translations of the names of regions and
27866  * areas if available. For example, if the locale property is given as "en-US" (English for USA), 
27867  * but the phone number being geolocated is in Germany, then this class would return the the names
27868  * of the country (Germany) and region inside of Germany in English instead of German. That is, a 
27869  * phone number in Munich and return the country "Germany" and the area code "Munich"
27870  * instead of "Deutschland" and "München". The default display locale is the current ilib locale. 
27871  * If translations are not available, the region and area names are given in English, which should 
27872  * always be available.
27873  * <li><i>mcc</i> The mcc of the current mobile carrier, if known.
27874  * 
27875  * <li><i>onLoad</i> - a callback function to call when the data for the
27876  * locale is fully loaded. When the onLoad option is given, this object 
27877  * will attempt to load any missing locale data using the ilib loader callback.
27878  * When the constructor is done (even if the data is already preassembled), the 
27879  * onLoad function is called with the current instance as a parameter, so this
27880  * callback can be used with preassembled or dynamic loading or a mix of the two. 
27881  * 
27882  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
27883  * asynchronously. If this option is given as "false", then the "onLoad"
27884  * callback must be given, as the instance returned from this constructor will
27885  * not be usable for a while. 
27886  *
27887  * <li><i>loadParams</i> - an object containing parameters to pass to the 
27888  * loader callback function when locale data is missing. The parameters are not
27889  * interpretted or modified in any way. They are simply passed along. The object 
27890  * may contain any property/value pairs as long as the calling code is in
27891  * agreement with the loader callback function as to what those parameters mean.
27892  * </ul>
27893  * 
27894  * @constructor
27895  * @param {Object} options parameters controlling the geolocation of the phone number.
27896  */
27897 var PhoneGeoLocator = function(options) {
27898 	var sync = true,
27899 		loadParams = {},
27900 		locale = ilib.getLocale();
27901 
27902 	if (options) {
27903 		if (options.locale) {
27904 			locale = options.locale;
27905 		}
27906 
27907 		if (typeof(options.sync) === 'boolean') {
27908 			sync = options.sync;
27909 		}
27910 		
27911 		if (options.loadParams) {
27912 			loadParams = options.loadParams;
27913 		}
27914 	}
27915 	
27916 	new PhoneLocale({
27917 		locale: locale,
27918 		mcc: options && options.mcc,
27919 		countryCode: options && options.countryCode,
27920 		sync: sync,
27921 		loadParams: loadParams,
27922 		onLoad: ilib.bind(this, function (loc) {
27923 			this.locale = loc;
27924 			new NumberingPlan({
27925 				locale: this.locale,
27926 				sync: sync,
27927 				loadParams: loadParams,
27928 				onLoad: ilib.bind(this, function (plan) {
27929 					this.plan = plan;
27930 					
27931 					new ResBundle({
27932 						locale: this.locale,
27933 						name: "phoneres",
27934 						sync: sync,
27935 						loadParams: loadParams,
27936 						onLoad: ilib.bind(this, function (rb) {
27937 							this.rb = rb;
27938 							
27939 							Utils.loadData({
27940 								name: "iddarea.json",
27941 								object: PhoneGeoLocator,
27942 								nonlocale: true,
27943 								sync: sync,
27944 								loadParams: loadParams,
27945 								callback: ilib.bind(this, function (data) {
27946 									this.regiondata = data;
27947 									Utils.loadData({
27948 										name: "area.json",
27949 										object: PhoneGeoLocator,
27950 										locale: this.locale,
27951 										sync: sync,
27952 										loadParams: JSUtils.merge(loadParams, {
27953 											returnOne: true
27954 										}),
27955 										callback: ilib.bind(this, function (areadata) {
27956 											this.areadata = areadata;
27957 		
27958 											if (options && typeof(options.onLoad) === 'function') {
27959 												options.onLoad(this);
27960 											}
27961 										})
27962 									});
27963 								})
27964 							});
27965 						})
27966 					});
27967 				})
27968 			});
27969 		})
27970 	});
27971 };
27972 
27973 PhoneGeoLocator.prototype = {
27974 	/**
27975 	 * @private
27976 	 * 
27977 	 * Used for locales where the area code is very general, and you need to add in
27978 	 * the initial digits of the subscriber number in order to get the area
27979 	 * 
27980 	 * @param {string} number
27981 	 * @param {Object} stateTable
27982 	 */
27983 	_parseAreaAndSubscriber: function (number, stateTable) {
27984 		var ch,
27985 			i,
27986 			handlerMethod,
27987 			newState,
27988 			prefix = "",
27989 			consumed,
27990 			lastLeaf,
27991 			currentState,
27992 			dot = 14;	// special transition which matches all characters. See AreaCodeTableMaker.java
27993 
27994 		if (!number || !stateTable) {
27995 			// can't parse anything
27996 			return undefined;
27997 		}
27998 
27999 		//console.log("GeoLocator._parseAreaAndSubscriber: parsing number " + number);
28000 
28001 		currentState = stateTable;
28002 		i = 0;
28003 		while (i < number.length) {
28004 			ch = PhoneNumber._getCharacterCode(number.charAt(i));
28005 			if (ch >= 0) {
28006 				// newState = stateData.states[state][ch];
28007 				newState = currentState.s && currentState.s[ch];
28008 				
28009 				if (!newState && currentState.s && currentState.s[dot]) {
28010 					newState = currentState.s[dot];
28011 				}
28012 				
28013 				if (typeof(newState) === 'object') {
28014 					if (typeof(newState.l) !== 'undefined') {
28015 						// save for latter if needed
28016 						lastLeaf = newState;
28017 						consumed = i;
28018 					}
28019 					// console.info("recognized digit " + ch + " continuing...");
28020 					// recognized digit, so continue parsing
28021 					currentState = newState;
28022 					i++;
28023 				} else {
28024 					if (typeof(newState) === 'undefined' || newState === 0) {
28025 						// this is possibly a look-ahead and it didn't work... 
28026 						// so fall back to the last leaf and use that as the
28027 						// final state
28028 						newState = lastLeaf;
28029 						i = consumed;
28030 					}
28031 					
28032 					if ((typeof(newState) === 'number' && newState) ||
28033 						(typeof(newState) === 'object' && typeof(newState.l) !== 'undefined')) {
28034 						// final state
28035 						var stateNumber = typeof(newState) === 'number' ? newState : newState.l;
28036 						handlerMethod = PhoneNumber._states[stateNumber];
28037 
28038 						//console.info("reached final state " + newState + " handler method is " + handlerMethod + " and i is " + i);
28039 	
28040 						return (handlerMethod === "area") ? number.substring(0, i+1) : undefined;
28041 					} else {
28042 						// failed parse. Either no last leaf to fall back to, or there was an explicit
28043 						// zero in the table
28044 						break;
28045 					}
28046 				}
28047 			} else if (ch === -1) {
28048 				// non-transition character, continue parsing in the same state
28049 				i++;
28050 			} else {
28051 				// should not happen
28052 				// console.info("skipping character " + ch);
28053 				// not a digit, plus, pound, or star, so this is probably a formatting char. Skip it.
28054 				i++;
28055 			}
28056 		}
28057 		return undefined;
28058 	},
28059 	/**
28060 	 * @private
28061 	 * @param prefix
28062 	 * @param table
28063 	 * @returns
28064 	 */
28065 	_matchPrefix: function(prefix, table)  {
28066 		var i, matchedDot, matchesWithDots = [];
28067 
28068 		if (table[prefix]) {
28069 			return table[prefix];
28070 		}
28071 		for (var entry in table) {
28072 			if (entry && typeof(entry) === 'string') {
28073 				i = 0;
28074 				matchedDot = false;
28075 				while (i < entry.length && (entry.charAt(i) === prefix.charAt(i) || entry.charAt(i) === '.')) {
28076 					if (entry.charAt(i) === '.') {
28077 						matchedDot = true;
28078 					}
28079 					i++;
28080 				}
28081 				if (i >= entry.length) {
28082 					if (matchedDot) {
28083 						matchesWithDots.push(entry);
28084 					} else {
28085 						return table[entry];
28086 					}
28087 				}
28088 			}
28089 		}
28090 
28091 		// match entries with dots last, so sort the matches so that the entry with the 
28092 		// most dots sorts last. The entry that ends up at the beginning of the list is
28093 		// the best match because it has the fewest dots
28094 		if (matchesWithDots.length > 0) {
28095 			matchesWithDots.sort(function (left, right) {
28096 				return (right < left) ? -1 : ((left < right) ? 1 : 0);
28097 			});
28098 			return table[matchesWithDots[0]];
28099 		}
28100 		
28101 		return undefined;
28102 	},
28103 	/**
28104 	 * @private
28105 	 * @param number
28106 	 * @param data
28107 	 * @param locale
28108 	 * @param plan
28109 	 * @param options
28110 	 * @returns {Object}
28111 	 */
28112 	_getAreaInfo: function(number, data, locale, plan, options) {
28113 		var sync = true,
28114 			ret = {}, 
28115 			countryCode, 
28116 			areaInfo, 
28117 			temp, 
28118 			areaCode, 
28119 			geoTable, 
28120 			tempNumber, 
28121 			prefix;
28122 
28123 		if (options && typeof(options.sync) === 'boolean') {
28124 			sync = options.sync;
28125 		}
28126 
28127 		prefix = number.areaCode || number.serviceCode;
28128 		geoTable = data;
28129 		
28130 		if (prefix !== undefined) {
28131 			if (plan.getExtendedAreaCode()) {
28132 				// for countries where the area code is very general and large, and you need a few initial
28133 				// digits of the subscriber number in order find the actual area
28134 				tempNumber = prefix + number.subscriberNumber;
28135 				tempNumber = tempNumber.replace(/[wWpPtT\+#\*]/g, '');	// fix for NOV-108200
28136 		
28137 				Utils.loadData({
28138 					name: "extarea.json",
28139 					object: PhoneGeoLocator, 
28140 					locale: locale,
28141 					sync: sync,
28142 					loadParams: JSUtils.merge((options && options.loadParams) || {}, {returnOne: true}),
28143 					callback: ilib.bind(this, function (data) {
28144 						this.extarea = data;
28145 						Utils.loadData({
28146 							name: "extstates.json",
28147 							object: PhoneGeoLocator, 
28148 							locale: locale,
28149 							sync: sync,
28150 							loadParams: JSUtils.merge((options && options.loadParams) || {}, {returnOne: true}),
28151 							callback: ilib.bind(this, function (data) {
28152 								this.extstates = data;
28153 								geoTable = this.extarea;
28154 								if (this.extarea && this.extstates) {
28155 									prefix = this._parseAreaAndSubscriber(tempNumber, this.extstates);
28156 								}
28157 								
28158 								if (!prefix) {
28159 									// not a recognized prefix, so now try the general table
28160 									geoTable = this.areadata;
28161 									prefix = number.areaCode || number.serviceCode;					
28162 								}
28163 
28164 								if ((!plan.fieldLengths || 
28165 								  plan.getFieldLength('maxLocalLength') === undefined ||
28166 								  !number.subscriberNumber ||
28167 								 	number.subscriberNumber.length <= plan.fieldLengths('maxLocalLength'))) {
28168 								  	areaInfo = this._matchPrefix(prefix, geoTable);
28169 									if (areaInfo && areaInfo.sn && areaInfo.ln) {
28170 										//console.log("Found areaInfo " + JSON.stringify(areaInfo));
28171 										ret.area = {
28172 											sn: this.rb.getString(areaInfo.sn).toString(),
28173 											ln: this.rb.getString(areaInfo.ln).toString()
28174 										};
28175 									}
28176 								}		
28177 							})
28178 						});
28179 					})
28180 				});
28181 
28182 			} else if (!plan || 
28183 					plan.getFieldLength('maxLocalLength') === undefined || 
28184 					!number.subscriberNumber ||
28185 					number.subscriberNumber.length <= plan.getFieldLength('maxLocalLength')) {
28186 				if (geoTable) {
28187 					areaCode = prefix.replace(/[wWpPtT\+#\*]/g, '');
28188 					areaInfo = this._matchPrefix(areaCode, geoTable);
28189 
28190 					if (areaInfo && areaInfo.sn && areaInfo.ln) {
28191 						ret.area = {
28192 							sn: this.rb.getString(areaInfo.sn).toString(),
28193 							ln: this.rb.getString(areaInfo.ln).toString()
28194 						};
28195 					} else if (number.serviceCode) {
28196 						ret.area = {
28197 							sn: this.rb.getString("Service Number").toString(),
28198 							ln: this.rb.getString("Service Number").toString()
28199 						};
28200 					}
28201 				} else {
28202 					countryCode = number.locale._mapRegiontoCC(this.locale.getRegion());
28203 					if (countryCode !== "0" && this.regiondata) {
28204 						temp = this.regiondata[countryCode];
28205 						if (temp && temp.sn) {
28206 							ret.country = {
28207 								sn: this.rb.getString(temp.sn).toString(),
28208 								ln: this.rb.getString(temp.ln).toString(),
28209 								code: this.locale.getRegion()
28210 							};
28211 						}
28212 					}
28213 				}
28214 			} else {
28215 				countryCode = number.locale._mapRegiontoCC(this.locale.getRegion());
28216 				if (countryCode !== "0" && this.regiondata) {
28217 					temp = this.regiondata[countryCode];
28218 					if (temp && temp.sn) {
28219 						ret.country = {
28220 							sn: this.rb.getString(temp.sn).toString(),
28221 							ln: this.rb.getString(temp.ln).toString(),
28222 							code: this.locale.getRegion()
28223 						};
28224 					}
28225 				}
28226 			}
28227 
28228 		} else if (number.mobilePrefix) {
28229 			ret.area = {
28230 				sn: this.rb.getString("Mobile Number").toString(),
28231 				ln: this.rb.getString("Mobile Number").toString()
28232 			};
28233 		} else if (number.emergency) {
28234 			ret.area = {
28235 				sn: this.rb.getString("Emergency Services Number").toString(),
28236 				ln: this.rb.getString("Emergency Services Number").toString()
28237 			};
28238 		}
28239 
28240 		return ret;
28241 	},
28242 	/**
28243 	 * Returns a the location of the given phone number, if known. 
28244 	 * The returned object has 2 properties, each of which has an sn (short name) 
28245 	 * and an ln (long name) string. Additionally, the country code, if given,
28246 	 * includes the 2 letter ISO code for the recognized country.
28247 	 *	 	{
28248 	 *			"country": {
28249 	 *	        	"sn": "North America",
28250 	 *            	"ln": "North America and the Caribbean Islands",
28251 	 *				"code": "us"
28252 	 *         	 },
28253 	 *         	 "area": {
28254 	 *       	    "sn": "California",
28255 	 *          	 "ln": "Central California: San Jose, Los Gatos, Milpitas, Sunnyvale, Cupertino, Gilroy"
28256 	 *         	 }
28257 	 *    	 }
28258 	 * 
28259 	 * The location name is subject to the following rules:
28260 	 *
28261 	 * If the areaCode property is undefined or empty, or if the number specifies a 
28262 	 * country code for which we do not have information, then the area property may be 
28263 	 * missing from the returned object. In this case, only the country object will be returned.
28264 	 *
28265 	 * If there is no area code, but there is a mobile prefix, service code, or emergency 
28266 	 * code, then a fixed string indicating the type of number will be returned.
28267 	 * 
28268 	 * The country object is filled out according to the countryCode property of the phone
28269 	 * number. 
28270 	 * 
28271 	 * If the phone number does not have an explicit country code, the MCC will be used if
28272 	 * it is available. The country code can be gleaned directly from the MCC. If the MCC 
28273 	 * of the carrier to which the phone is currently connected is available, it should be 
28274 	 * passed in so that local phone numbers will look correct.
28275 	 * 
28276 	 * If the country's dialling plan mandates a fixed length for phone numbers, and a 
28277 	 * particular number exceeds that length, then the area code will not be given on the
28278 	 * assumption that the number has problems in the first place and we cannot guess
28279 	 * correctly.
28280 	 *
28281 	 * The returned area property varies in specificity according
28282 	 * to the locale. In North America, the area is no finer than large parts of states
28283 	 * or provinces. In Germany and the UK, the area can be as fine as small towns.
28284 	 *
28285 	 * The strings returned from this function are already localized to the 
28286 	 * given locale, and thus are ready for display to the user.
28287 	 *
28288 	 * If the number passed in is invalid, an empty object is returned. If the location
28289 	 * information about the country where the phone number is located is not available,
28290 	 * then the area information will be missing and only the country will be returned.
28291      *
28292 	 * The options parameter can contain any one of the following properties:
28293  	 * 
28294  	 * <ul>
28295  	 * <li><i>locale</i> The locale parameter is used to load translations of the names of regions and
28296  	 * areas if available. For example, if the locale property is given as "en-US" (English for USA), 
28297  	 * but the phone number being geolocated is in Germany, then this class would return the the names
28298  	 * of the country (Germany) and region inside of Germany in English instead of German. That is, a 
28299  	 * phone number in Munich and return the country "Germany" and the area code "Munich"
28300  	 * instead of "Deutschland" and "München". The default display locale is the current ilib locale. 
28301  	 * If translations are not available, the region and area names are given in English, which should 
28302  	 * always be available.
28303  	 * <li><i>mcc</i> The mcc of the current mobile carrier, if known.
28304  	 * 
28305  	 * <li><i>onLoad</i> - a callback function to call when the data for the
28306  	 * locale is fully loaded. When the onLoad option is given, this object 
28307  	 * will attempt to load any missing locale data using the ilib loader callback.
28308  	 * When the constructor is done (even if the data is already preassembled), the 
28309  	 * onLoad function is called with the current instance as a parameter, so this
28310  	 * callback can be used with preassembled or dynamic loading or a mix of the two. 
28311  	 * 
28312  	 * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
28313  	 * asynchronously. If this option is given as "false", then the "onLoad"
28314  	 * callback must be given, as the instance returned from this constructor will
28315  	 * not be usable for a while. 
28316  	 *
28317  	 * <li><i>loadParams</i> - an object containing parameters to pass to the 
28318  	 * loader callback function when locale data is missing. The parameters are not
28319  	 * interpretted or modified in any way. They are simply passed along. The object 
28320  	 * may contain any property/value pairs as long as the calling code is in
28321  	 * agreement with the loader callback function as to what those parameters mean.
28322  	 * </ul>
28323 	 * 
28324 	 * @param {PhoneNumber} number phone number to locate
28325 	 * @param {Object} options options governing the way this ares is loaded
28326 	 * @return {Object} an object  
28327 	 * that describes the country and the area in that country corresponding to this
28328 	 * phone number. Each of the country and area contain a short name (sn) and long
28329 	 * name (ln) that describes the location.
28330 	 */
28331 	locate: function(number, options) {
28332 		var loadParams = {},
28333 			ret = {}, 
28334 			region, 
28335 			countryCode, 
28336 			temp, 
28337 			plan,
28338 			areaResult,
28339 			phoneLoc = this.locale,
28340 			sync = true;
28341 
28342 		if (number === undefined || typeof(number) !== 'object' || !(number instanceof PhoneNumber)) {
28343 			return ret;
28344 		}
28345 
28346 		if (options) {
28347 			if (typeof(options.sync) !== 'undefined') {
28348 				sync = (options.sync == true);
28349 			}
28350 		
28351 			if (options.loadParams) {
28352 				loadParams = options.loadParams;
28353 			}
28354 		}
28355 
28356 		// console.log("GeoLocator.locate: looking for geo for number " + JSON.stringify(number));
28357 		region = this.locale.getRegion();
28358 		if (number.countryCode !== undefined && this.regiondata) {
28359 			countryCode = number.countryCode.replace(/[wWpPtT\+#\*]/g, '');
28360 			temp = this.regiondata[countryCode];
28361 			phoneLoc = number.destinationLocale;
28362 			plan = number.destinationPlan;
28363 			ret.country = {
28364 				sn: this.rb.getString(temp.sn).toString(),
28365 				ln: this.rb.getString(temp.ln).toString(),
28366 				code: phoneLoc.getRegion()
28367 			};
28368 		}
28369 		
28370 		if (!plan) {
28371 			plan = this.plan;
28372 		}
28373 		
28374 		Utils.loadData({
28375 			name: "area.json",
28376 			object: PhoneGeoLocator,
28377 			locale: phoneLoc,
28378 			sync: sync,
28379 			loadParams: JSUtils.merge(loadParams, {
28380 				returnOne: true
28381 			}),
28382 			callback: ilib.bind(this, function (areadata) {
28383 				if (areadata) {
28384 					this.areadata = areadata;	
28385 				}
28386 				areaResult = this._getAreaInfo(number, this.areadata, phoneLoc, plan, options);
28387 				ret = JSUtils.merge(ret, areaResult);
28388 
28389 				if (ret.country === undefined) {
28390 					countryCode = number.locale._mapRegiontoCC(region);
28391 					
28392 					if (countryCode !== "0" && this.regiondata) {
28393 						temp = this.regiondata[countryCode];
28394 						if (temp && temp.sn) {
28395 							ret.country = {
28396 								sn: this.rb.getString(temp.sn).toString(),
28397 								ln: this.rb.getString(temp.ln).toString(),
28398 								code: this.locale.getRegion()
28399 							};
28400 						}
28401 					}
28402 				}
28403 			})
28404 		});
28405 		
28406 		return ret;
28407 	},
28408 	
28409 	/**
28410 	 * Returns a string that describes the ISO-3166-2 country code of the given phone
28411 	 * number.<p> 
28412 	 * 
28413 	 * If the phone number is a local phone number and does not contain
28414 	 * any country information, this routine will return the region for the current
28415 	 * formatter instance.
28416      *
28417 	 * @param {PhoneNumber} number An PhoneNumber instance
28418 	 * @return {string}
28419 	 */
28420 	country: function(number) {
28421 		var countryCode,
28422 			region,
28423 			phoneLoc;
28424 
28425 		if (!number || !(number instanceof PhoneNumber)) {
28426 			return "";
28427 		}
28428 
28429 		phoneLoc = number.locale;
28430 
28431 		region = (number.countryCode && phoneLoc._mapCCtoRegion(number.countryCode)) ||
28432 			(number.locale && number.locale.region) || 
28433 			phoneLoc.locale.getRegion() ||
28434 			this.locale.getRegion();
28435 
28436 		countryCode = number.countryCode || phoneLoc._mapRegiontoCC(region);
28437 		
28438 		if (number.areaCode) {
28439 			region = phoneLoc._mapAreatoRegion(countryCode, number.areaCode);
28440 		} else if (countryCode === "33" && number.serviceCode) {
28441 			// french departments are in the service code, not the area code
28442 			region = phoneLoc._mapAreatoRegion(countryCode, number.serviceCode);
28443 		}		
28444 		return region;
28445 	}
28446 };
28447 
28448 
28449 /*< Measurement.js */
28450 /*
28451  * Measurement.js - Measurement unit superclass
28452  * 
28453  * Copyright © 2014-2015, JEDLSoft
28454  *
28455  * Licensed under the Apache License, Version 2.0 (the "License");
28456  * you may not use this file except in compliance with the License.
28457  * You may obtain a copy of the License at
28458  *
28459  *     http://www.apache.org/licenses/LICENSE-2.0
28460  *
28461  * Unless required by applicable law or agreed to in writing, software
28462  * distributed under the License is distributed on an "AS IS" BASIS,
28463  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
28464  *
28465  * See the License for the specific language governing permissions and
28466  * limitations under the License.
28467  */
28468 
28469 /**
28470  * @class
28471  * Superclass for measurement instances that contains shared functionality
28472  * and defines the interface. <p>
28473  * 
28474  * This class is never instantiated on its own. Instead, measurements should
28475  * be created using the {@link MeasurementFactory} function, which creates the
28476  * correct subclass based on the given parameters.<p>
28477  * 
28478  * @private
28479  * @constructor 
28480  */
28481 var Measurement = function() {
28482 };
28483 
28484 /**
28485  * @private
28486  */
28487 Measurement._constructors = {};
28488 
28489 Measurement.prototype = {
28490 	/**
28491 	 * Return the normalized name of the given units. If the units are
28492 	 * not recognized, this method returns its parameter unmodified.<p>
28493 	 * 
28494 	 * Examples:
28495 	 * 
28496 	 * <ui>
28497 	 * <li>"metres" gets normalized to "meter"<br>
28498 	 * <li>"ml" gets normalized to "milliliter"<br>
28499 	 * <li>"foobar" gets normalized to "foobar" (no change because it is not recognized)
28500 	 * </ul>
28501 	 *  
28502 	 * @param {string} name name of the units to normalize. 
28503 	 * @returns {string} normalized name of the units
28504 	 */
28505 	normalizeUnits: function(name) {
28506 		return this.aliases[name] || name;
28507 	},
28508 
28509 	/**
28510 	 * Return the normalized units used in this measurement.
28511 	 * @return {string} name of the unit of measurement 
28512 	 */
28513 	getUnit: function() {
28514 		return this.unit;
28515 	},
28516      
28517 	/**
28518 	 * Return the units originally used to construct this measurement
28519 	 * before it was normalized.
28520 	 * @return {string} name of the unit of measurement 
28521 	 */
28522 	getOriginalUnit: function() {
28523 		return this.originalUnit;
28524 	},
28525 	
28526 	/**
28527 	 * Return the numeric amount of this measurement.
28528 	 * @return {number} the numeric amount of this measurement
28529 	 */
28530 	getAmount: function() {
28531 		return this.amount;
28532 	},
28533 	
28534 	/**
28535 	 * Return the type of this measurement. Examples are "mass",
28536 	 * "length", "speed", etc. Measurements can only be converted
28537 	 * to measurements of the same type.<p>
28538 	 * 
28539 	 * The type of the units is determined automatically from the 
28540 	 * units. For example, the unit "grams" is type "mass". Use the 
28541 	 * static call {@link Measurement.getAvailableUnits}
28542 	 * to find out what units this version of ilib supports.
28543 	 * 
28544 	 * @return {string} the name of the type of this measurement
28545 	 */
28546 	getMeasure: function() {},
28547 	
28548 	/**
28549 	 * Return a new measurement instance that is converted to a new
28550 	 * measurement unit. Measurements can only be converted
28551 	 * to measurements of the same type.<p>
28552 	 * 
28553 	 * @param {string} to The name of the units to convert to
28554 	 * @return {Measurement|undefined} the converted measurement
28555 	 * or undefined if the requested units are for a different
28556 	 * measurement type
28557 	 */
28558 	convert: function(to) {},     
28559         
28560     /**
28561 	 * Scale the measurement unit to an acceptable level. The scaling
28562 	 * happens so that the integer part of the amount is as small as
28563 	 * possible without being below zero. This will result in the 
28564 	 * largest units that can represent this measurement without
28565 	 * fractions. Measurements can only be scaled to other measurements 
28566 	 * of the same type.
28567 	 * 
28568 	 * @param {string=} measurementsystem system to use (uscustomary|imperial|metric),
28569 	 * or undefined if the system can be inferred from the current measure
28570 	 * @return {Measurement} a new instance that is scaled to the 
28571 	 * right level
28572 	 */
28573 	scale: function(measurementsystem) {},
28574         
28575 	/**
28576 	 * Localize the measurement to the commonly used measurement in that locale, for example
28577 	 * If a user's locale is "en-US" and the measurement is given as "60 kmh", 
28578 	 * the formatted number should be automatically converted to the most appropriate 
28579 	 * measure in the other system, in this case, mph. The formatted result should
28580 	 * appear as "37.3 mph". 
28581 	 * 
28582 	 * @param {string} locale current locale string
28583 	 * @returns {Measurement} a new instance that is converted to locale
28584 	 */
28585 	localize: function(locale) {}
28586 };
28587 
28588 
28589 
28590 /*< UnknownUnit.js */
28591 /*
28592  * Unknown.js - Dummy unit conversions for unknown types
28593  * 
28594  * Copyright © 2014-2015, JEDLSoft
28595  *
28596  * Licensed under the Apache License, Version 2.0 (the "License");
28597  * you may not use this file except in compliance with the License.
28598  * You may obtain a copy of the License at
28599  *
28600  *     http://www.apache.org/licenses/LICENSE-2.0
28601  *
28602  * Unless required by applicable law or agreed to in writing, software
28603  * distributed under the License is distributed on an "AS IS" BASIS,
28604  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
28605  *
28606  * See the License for the specific language governing permissions and
28607  * limitations under the License.
28608  */
28609 
28610 // !depends Measurement.js
28611 
28612 
28613 /**
28614  * @class
28615  * Create a new unknown measurement instance.
28616  * 
28617  * @constructor
28618  * @extends Measurement
28619  * @param options {{unit:string,amount:number|string|undefined}} Options controlling 
28620  * the construction of this instance
28621  */
28622 var UnknownUnit = function (options) {
28623 	if (options) {
28624 		this.unit = options.unit;
28625 		this.amount = options.amount;
28626 	}
28627 };
28628 
28629 UnknownUnit.prototype = new Measurement();
28630 UnknownUnit.prototype.parent = Measurement;
28631 UnknownUnit.prototype.constructor = UnknownUnit;
28632 
28633 UnknownUnit.aliases = {
28634 	"unknown":"unknown"
28635 };
28636 
28637 /**
28638  * Return the type of this measurement. Examples are "mass",
28639  * "length", "speed", etc. Measurements can only be converted
28640  * to measurements of the same type.<p>
28641  * 
28642  * The type of the units is determined automatically from the 
28643  * units. For example, the unit "grams" is type "mass". Use the 
28644  * static call {@link Measurement.getAvailableUnits}
28645  * to find out what units this version of ilib supports.
28646  *  
28647  * @return {string} the name of the type of this measurement
28648  */
28649 UnknownUnit.prototype.getMeasure = function() {
28650 	return "unknown";
28651 };
28652 
28653 /**
28654  * Return a new measurement instance that is converted to a new
28655  * measurement unit. Measurements can only be converted
28656  * to measurements of the same type.<p>
28657  *  
28658  * @param {string} to The name of the units to convert to
28659  * @return {Measurement|undefined} the converted measurement
28660  * or undefined if the requested units are for a different
28661  * measurement type 
28662  */
28663 UnknownUnit.prototype.convert = function(to) {
28664 	return undefined;
28665 };
28666 
28667 /**
28668  * Convert a unknown to another measure.
28669  * @static
28670  * @param {string} to unit to convert to
28671  * @param {string} from unit to convert from
28672  * @param {number} unknown amount to be convert
28673  * @returns {number|undefined} the converted amount
28674  */
28675 UnknownUnit.convert = function(to, from, unknown) {
28676     return undefined;
28677 };
28678 
28679 /**
28680  * Localize the measurement to the commonly used measurement in that locale. For example
28681  * If a user's locale is "en-US" and the measurement is given as "60 kmh", 
28682  * the formatted number should be automatically converted to the most appropriate 
28683  * measure in the other system, in this case, mph. The formatted result should
28684  * appear as "37.3 mph". 
28685  * 
28686  * @param {string} locale current locale string
28687  * @returns {Measurement} a new instance that is converted to locale
28688  */
28689 UnknownUnit.prototype.localize = function(locale) {
28690     return new UnknownUnit({
28691         unit: this.unit,
28692         amount: this.amount
28693     });
28694 };
28695 
28696 /**
28697  * Scale the measurement unit to an acceptable level. The scaling
28698  * happens so that the integer part of the amount is as small as
28699  * possible without being below zero. This will result in the 
28700  * largest units that can represent this measurement without
28701  * fractions. Measurements can only be scaled to other measurements 
28702  * of the same type.
28703  * 
28704  * @param {string=} measurementsystem system to use (uscustomary|imperial|metric),
28705  * or undefined if the system can be inferred from the current measure
28706  * @return {Measurement} a new instance that is scaled to the 
28707  * right level
28708  */
28709 UnknownUnit.prototype.scale = function(measurementsystem) {
28710     return new UnknownUnit({
28711         unit: this.unit,
28712         amount: this.amount
28713     }); 
28714 };
28715 
28716 /**
28717  * @private
28718  * @static
28719  */
28720 UnknownUnit.getMeasures = function () {
28721 	return [];
28722 };
28723 
28724 
28725 /*< AreaUnit.js */
28726 /*
28727  * area.js - Unit conversions for Area
28728  * 
28729  * Copyright © 2014-2015, JEDLSoft
28730  *
28731  * Licensed under the Apache License, Version 2.0 (the "License");
28732  * you may not use this file except in compliance with the License.
28733  * You may obtain a copy of the License at
28734  *
28735  *     http://www.apache.org/licenses/LICENSE-2.0
28736  *
28737  * Unless required by applicable law or agreed to in writing, software
28738  * distributed under the License is distributed on an "AS IS" BASIS,
28739  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
28740  *
28741  * See the License for the specific language governing permissions and
28742  * limitations under the License.
28743  */
28744 
28745 /*
28746 !depends 
28747 Measurement.js
28748 */
28749 
28750 
28751 /**
28752  * @class
28753  * Create a new area measurement instance.
28754  * @constructor
28755  * @extends Measurement
28756  * @param options {{unit:string,amount:number|string|undefined}} Options controlling 
28757  * the construction of this instance
28758  */
28759 var AreaUnit = function (options) {
28760 	this.unit = "square meter";
28761 	this.amount = 0;
28762 	this.aliases = AreaUnit.aliases; // share this table in all instances
28763 	
28764 	if (options) {
28765 		if (typeof(options.unit) !== 'undefined') {
28766 			this.originalUnit = options.unit;
28767 			this.unit = this.aliases[options.unit] || options.unit;
28768 		}
28769 		
28770 		if (typeof(options.amount) === 'object') {
28771 			if (options.amount.getMeasure() === "area") {
28772 				this.amount = AreaUnit.convert(this.unit, options.amount.getUnit(), options.amount.getAmount());
28773 			} else {
28774 				throw "Cannot convert unit " + options.amount.unit + " to area";
28775 			}
28776 		} else if (typeof(options.amount) !== 'undefined') {
28777 			this.amount = parseFloat(options.amount);
28778 		}
28779 	}
28780 	
28781 	if (typeof(AreaUnit.ratios[this.unit]) === 'undefined') {
28782 		throw "Unknown unit: " + options.unit;
28783 	}
28784 };
28785 
28786 AreaUnit.prototype = new Measurement();
28787 AreaUnit.prototype.parent = Measurement;
28788 AreaUnit.prototype.constructor = AreaUnit;
28789 
28790 AreaUnit.ratios = {
28791     /*               index		square cm,		square meter,   hectare,   	square km, 	, square inch 	square foot, 		square yard, 	  	  		acre,			square mile			        */
28792     "square centimeter":[1,   	1,				0.0001,			1e-8,	    1e-10,        0.15500031,	0.00107639104,		0.000119599005,			2.47105381e-8,		3.86102159e-11 		],
28793     "square meter": 	[2,   	10000,			1,              1e-4,       1e-6,         1550,    	 	10.7639,    	  	1.19599,   				0.000247105,		3.861e-7     	    ],
28794     "hectare":      	[3,	 	100000000,  	10000,          1,          0.01,         1.55e+7, 	  	107639,     	 	11959.9,   				2.47105	,			0.00386102    	    ],
28795     "square km":    	[4,	  	10000000000, 	1e+6,          	100,        1,	          1.55e+9, 	  	1.076e+7,   	 	1.196e+6,  				247.105 ,   		0.386102     	    ],
28796     "square inch":  	[5,	  	6.4516,			0.00064516,     6.4516e-8,  6.4516e-10,   1,			0.000771605,	  	0.0007716051, 			1.5942e-7,			2.491e-10    	    ],
28797     "square foot":  	[6,		929.0304,		0.092903,       9.2903e-6,  9.2903e-8,    144,			1,          	  	0.111111,  				2.2957e-5,			3.587e-8    		],
28798     "square yard":  	[7,		8361.2736,		0.836127,       8.3613e-5,  8.3613e-7,    1296,    	  	9,          	  	1,         				0.000206612,		3.2283e-7    	    ],
28799     "acre":         	[8,		40468564.2,		4046.86,        0.404686,   0.00404686,   6.273e+6,	  	43560,      	  	4840,      				1,		    		0.0015625    	    ],
28800     "square mile":  	[9,	   	2.58998811e+10,	2.59e+6,        258.999,    2.58999,      4.014e+9,	 	2.788e+7,   	  	3.098e+6,  				640,     			1   	     		]
28801 }
28802 
28803 /**
28804  * Return the type of this measurement. Examples are "mass",
28805  * "length", "speed", etc. Measurements can only be converted
28806  * to measurements of the same type.<p>
28807  * 
28808  * The type of the units is determined automatically from the 
28809  * units. For example, the unit "grams" is type "mass". Use the 
28810  * static call {@link Measurement.getAvailableUnits}
28811  * to find out what units this version of ilib supports.
28812  *  
28813  * @return {string} the name of the type of this measurement
28814  */
28815 AreaUnit.prototype.getMeasure = function() {
28816 	return "area";
28817 }; 
28818 
28819 /**
28820  * Return a new measurement instance that is converted to a new
28821  * measurement unit. Measurements can only be converted
28822  * to measurements of the same type.<p>
28823  *  
28824  * @param {string} to The name of the units to convert to
28825  * @return {Measurement|undefined} the converted measurement
28826  * or undefined if the requested units are for a different
28827  * measurement type
28828  * 
28829  */
28830 AreaUnit.prototype.convert = function(to) {
28831 	if (!to || typeof(AreaUnit.ratios[this.normalizeUnits(to)]) === 'undefined') {
28832 		return undefined;
28833 	}
28834 	return new AreaUnit({
28835 		unit: to, 
28836 		amount: this
28837 	});
28838 };
28839 
28840 AreaUnit.aliases = {
28841     "square centimeter":"square centimeter",
28842     "square cm":"square centimeter",
28843     "sq cm":"square centimeter",
28844     "Square Cm":"square centimeter",
28845     "square Centimeters":"square centimeter",
28846     "square Centimeter":"square centimeter",
28847     "square Centimetre":"square centimeter",
28848     "square Centimetres":"square centimeter",
28849     "square centimeters":"square centimeter",
28850     "Square km": "square km",
28851 	"Square kilometre":"square km",
28852 	"square kilometer":"square km",
28853 	"square kilometre":"square km",
28854 	"square kilometers":"square km",
28855 	"square kilometres":"square km",
28856     "square km":"square km",
28857 	"sq km":"square km",
28858 	"km2":"square km",
28859 	"Hectare":"hectare",
28860 	"hectare":"hectare",
28861 	"ha":"hectare",
28862 	"Square meter": "square meter",
28863 	"Square meters":"square meter",
28864 	"square meter": "square meter",
28865 	"square meters":"square meter",
28866 	"Square metre": "square meter",
28867 	"Square metres":"square meter",
28868 	"square metres": "square meter",
28869 	"Square Metres":"square meter",
28870 	"sqm":"square meter",
28871 	"m2": "square meter",
28872 	"Square mile":"square mile",
28873 	"Square miles":"square mile",
28874 	"square mile":"square mile",
28875 	"square miles":"square mile",
28876 	"square mi":"square mile",
28877 	"Square mi":"square mile",
28878 	"sq mi":"square mile",
28879 	"mi2":"square mile",
28880 	"Acre": "acre",
28881 	"acre": "acre",
28882 	"Acres":"acre",
28883 	"acres":"acre",
28884 	"Square yard": "square yard",
28885 	"Square yards":"square yard",
28886 	"square yard": "square yard",
28887 	"square yards":"square yard",
28888 	"yd2":"square yard",
28889 	"Square foot": "square foot",
28890 	"square foot": "square foot",
28891 	"Square feet": "square foot",
28892 	"Square Feet": "square foot",
28893 	"sq ft":"square foot",
28894 	"ft2":"square foot",
28895 	"Square inch":"square inch",
28896 	"square inch":"square inch",
28897 	"Square inches":"square inch",
28898 	"square inches":"square inch",
28899 	"in2":"square inch"
28900 };
28901 
28902 /**
28903  * Convert a Area to another measure.
28904  * @static
28905  * @param to {string} unit to convert to
28906  * @param from {string} unit to convert from
28907  * @param area {number} amount to be convert
28908  * @returns {number|undefined} the converted amount
28909  */
28910 AreaUnit.convert = function(to, from, area) {
28911     from = AreaUnit.aliases[from] || from;
28912     to = AreaUnit.aliases[to] || to;
28913 	var fromRow = AreaUnit.ratios[from];
28914 	var toRow = AreaUnit.ratios[to];
28915 	if (typeof(from) === 'undefined' || typeof(to) === 'undefined') {
28916 		return undefined;
28917 	}
28918 	return area* fromRow[toRow[0]];
28919 };
28920 
28921 /**
28922  * @private
28923  * @static
28924  */
28925 AreaUnit.getMeasures = function () {
28926 	var ret = [];
28927 	for (var m in AreaUnit.ratios) {
28928 		ret.push(m);
28929 	}
28930 	return ret;
28931 };
28932 
28933 AreaUnit.metricSystem = {
28934 	"square centimeter" : 1,
28935 	"square meter" : 2,
28936 	"hectare" : 3,
28937 	"square km" : 4
28938 };
28939 AreaUnit.imperialSystem = {
28940 	"square inch" : 5,
28941 	"square foot" : 6,
28942 	"square yard" : 7,
28943 	"acre" : 8,
28944 	"square mile" : 9
28945 };
28946 AreaUnit.uscustomarySystem = {
28947 	"square inch" : 5,
28948 	"square foot" : 6,
28949 	"square yard" : 7,
28950 	"acre" : 8,
28951 	"square mile" : 9
28952 };
28953 
28954 AreaUnit.metricToUScustomary = {
28955 	"square centimeter" : "square inch",
28956 	"square meter" : "square yard",
28957 	"hectare" : "acre",
28958 	"square km" : "square mile"
28959 };
28960 AreaUnit.usCustomaryToMetric = {
28961 	"square inch" : "square centimeter",
28962 	"square foot" : "square meter",
28963 	"square yard" : "square meter",
28964 	"acre" : "hectare",
28965 	"square mile" : "square km"
28966 };
28967 
28968 
28969 /**
28970  * Scale the measurement unit to an acceptable level. The scaling
28971  * happens so that the integer part of the amount is as small as
28972  * possible without being below zero. This will result in the 
28973  * largest units that can represent this measurement without
28974  * fractions. Measurements can only be scaled to other measurements 
28975  * of the same type.
28976  * 
28977  * @param {string=} measurementsystem system to use (uscustomary|imperial|metric),
28978  * or undefined if the system can be inferred from the current measure
28979  * @return {Measurement} a new instance that is scaled to the 
28980  * right level
28981  */
28982 AreaUnit.prototype.scale = function(measurementsystem) {
28983     var fromRow = AreaUnit.ratios[this.unit];
28984     var mSystem;
28985 
28986     if (measurementsystem === "metric" || (typeof(measurementsystem) === 'undefined'
28987         && typeof(AreaUnit.metricSystem[this.unit]) !== 'undefined')) {
28988         mSystem = AreaUnit.metricSystem;
28989     } else if (measurementsystem === "uscustomary" || (typeof(measurementsystem) === 'undefined'
28990         && typeof(AreaUnit.uscustomarySystem[this.unit]) !== 'undefined')) {
28991         mSystem = AreaUnit.uscustomarySystem;
28992     } else if (measurementsystem === "imperial" || (typeof(measurementsystem) === 'undefined'
28993         && typeof(AreaUnit.imperialSystem[this.unit]) !== 'undefined')) {
28994         mSystem = AreaUnit.imperialSystem;
28995     }
28996 
28997     var area = this.amount;
28998     var munit = this.unit;
28999 
29000     area = 18446744073709551999;
29001     
29002     for (var m in mSystem) {
29003         var tmp = this.amount * fromRow[mSystem[m]];
29004         if (tmp >= 1 && tmp < area) {
29005 	        area = tmp;
29006 	        munit = m;
29007         }
29008     }
29009 
29010     return new AreaUnit({
29011         unit: munit,
29012         amount: area
29013     });
29014 };
29015 
29016 /**
29017  * Localize the measurement to the commonly used measurement in that locale. For example
29018  * If a user's locale is "en-US" and the measurement is given as "60 kmh", 
29019  * the formatted number should be automatically converted to the most appropriate 
29020  * measure in the other system, in this case, mph. The formatted result should
29021  * appear as "37.3 mph". 
29022  * 
29023  * @param {string} locale current locale string
29024  * @returns {Measurement} a new instance that is converted to locale
29025  */
29026 AreaUnit.prototype.localize = function(locale) {
29027     var to;
29028     if (locale === "en-US" || locale === "en-GB") {
29029         to = AreaUnit.metricToUScustomary[this.unit] || this.unit;
29030     } else {
29031         to = AreaUnit.usCustomaryToMetric[this.unit] || this.unit;
29032     }
29033     return new AreaUnit({
29034         unit: to,
29035         amount: this
29036     });
29037 };
29038 
29039 
29040 //register with the factory method
29041 Measurement._constructors["area"] = AreaUnit;
29042 
29043 
29044 /*< DigitalStorageUnit.js */
29045 /*
29046  * digitalStorage.js - Unit conversions for Digital Storage
29047  * 
29048  * Copyright © 2014-2015, JEDLSoft
29049  *
29050  * Licensed under the Apache License, Version 2.0 (the "License");
29051  * you may not use this file except in compliance with the License.
29052  * You may obtain a copy of the License at
29053  *
29054  *     http://www.apache.org/licenses/LICENSE-2.0
29055  *
29056  * Unless required by applicable law or agreed to in writing, software
29057  * distributed under the License is distributed on an "AS IS" BASIS,
29058  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29059  *
29060  * See the License for the specific language governing permissions and
29061  * limitations under the License.
29062  */
29063 
29064 /*
29065 !depends 
29066 Measurement.js
29067 */
29068 
29069 
29070 /**
29071  * @class
29072  * Create a new DigitalStorage measurement instance.
29073  *  
29074  * @constructor
29075  * @extends Measurement
29076  * @param options {{unit:string,amount:number|string|undefined}} Options controlling 
29077  * the construction of this instance
29078  */
29079 var DigitalStorageUnit = function (options) {
29080 	this.unit = "byte";
29081 	this.amount = 0;
29082 	this.aliases = DigitalStorageUnit.aliases; // share this table in all instances
29083 	
29084 	if (options) {
29085 		if (typeof(options.unit) !== 'undefined') {
29086 			this.originalUnit = options.unit;
29087 			this.unit = this.aliases[options.unit] || options.unit;
29088 		}
29089 		
29090 		if (typeof(options.amount) === 'object') {
29091 			if (options.amount.getMeasure() === "digitalStorage") {
29092 				this.amount = DigitalStorageUnit.convert(this.unit, options.amount.getUnit(), options.amount.getAmount());
29093 			} else {
29094 				throw "Cannot convert unit " + options.amount.unit + " to a digitalStorage";
29095 			}
29096 		} else if (typeof(options.amount) !== 'undefined') {
29097 			this.amount = parseFloat(options.amount);
29098 		}
29099 	}
29100 	
29101 	if (typeof(DigitalStorageUnit.ratios[this.unit]) === 'undefined') {
29102 		throw "Unknown unit: " + options.unit;
29103 	}
29104 };
29105 
29106 DigitalStorageUnit.prototype = new Measurement();
29107 DigitalStorageUnit.prototype.parent = Measurement;
29108 DigitalStorageUnit.prototype.constructor = DigitalStorageUnit;
29109 
29110 DigitalStorageUnit.ratios = {
29111     /*            #    bit             byte            kb              kB              mb              mB              gb               gB               tb               tB               pb               pB   */           
29112 	"bit":      [ 1,   1,              0.125,          0.0009765625,   1.220703125e-4, 9.536743164e-7, 1.192092896e-7, 9.313225746e-10, 1.164153218e-10, 9.094947017e-13, 1.136868377e-13, 8.881784197e-16, 1.110223025e-16 ],
29113     "byte":     [ 2,   8,              1,              0.0078125,      0.0009765625,   7.629394531e-6, 9.536743164e-7, 7.450580597e-9,  9.313225746e-10, 7.275957614e-12, 9.094947017e-13, 7.105427358e-15, 8.881784197e-16 ],
29114     "kilobit":  [ 3,   1024,           128,            1,              0.125,          0.0009765625,   1.220703125e-4, 9.536743164e-7,  1.192092896e-7,  9.313225746e-10, 1.164153218e-10, 9.094947017e-13, 1.136868377e-13 ],
29115     "kilobyte": [ 4,   8192,           1024,           8,              1,              0.0078125,      0.0009765625,   7.629394531e-6,  9.536743164e-7,  7.450580597e-9,  9.313225746e-10, 7.275957614e-12, 9.094947017e-13 ],
29116     "megabit":  [ 5,   1048576,        131072,         1024,           128,            1,              0.125,          0.0009765625,    1.220703125e-4,  9.536743164e-7,  1.192092896e-7,  9.313225746e-10, 1.164153218e-10 ],
29117     "megabyte": [ 6,   8388608,        1048576,        8192,           1024,           8,              1,              0.0078125,       0.0009765625,    7.629394531e-6,  9.536743164e-7,  7.450580597e-9,  9.313225746e-10 ],
29118     "gigabit":  [ 7,   1073741824,     134217728,      1048576,        131072,         1024,           128,            1,               0.125,           0.0009765625,    1.220703125e-4,  9.536743164e-7,  1.192092896e-7  ],
29119     "gigabyte": [ 8,   8589934592,     1073741824,     8388608,        1048576,        8192,           1024,           8,               1,               0.0078125,       0.0009765625,    7.629394531e-6,  9.536743164e-7  ],
29120     "terabit":  [ 9,   1.099511628e12, 137438953472,   1073741824,     134217728,      1048576,        131072,         1024,            128,             1,               0.125,           0.0009765625,    1.220703125e-4  ],
29121     "terabyte": [ 10,  8.796093022e12, 1.099511628e12, 8589934592,     1073741824,     8388608,        1048576,        8192,            1024,            8,               1,               0.0078125,       0.0009765625    ],
29122     "petabit":  [ 11,  1.125899907e15, 1.407374884e14, 1.099511628e12, 137438953472,   1073741824,     134217728,      1048576,         131072,          1024,            128,             1,               0.125           ],
29123     "petabyte": [ 12,  9.007199255e15, 1.125899907e15, 8.796093022e12, 1.099511628e12, 8589934592,     1073741824,     8388608,         1048576,         8192,            1024,            8,               1               ]
29124 };
29125 
29126 DigitalStorageUnit.bitSystem = {
29127     "bit":      1,
29128     "kilobit":  3,
29129     "megabit":  5,
29130     "gigabit":  7,
29131     "terabit":  9,
29132     "petabit":  11
29133 };
29134 DigitalStorageUnit.byteSystem = {
29135     "byte":     2,
29136     "kilobyte": 4,
29137     "megabyte": 6,
29138     "gigabyte": 8,
29139     "terabyte": 10,
29140     "petabyte": 12
29141 };
29142 
29143 /**
29144  * Return the type of this measurement. Examples are "mass",
29145  * "length", "speed", etc. Measurements can only be converted
29146  * to measurements of the same type.<p>
29147  * 
29148  * The type of the units is determined automatically from the 
29149  * units. For example, the unit "grams" is type "mass". Use the 
29150  * static call {@link Measurement.getAvailableUnits}
29151  * to find out what units this version of ilib supports.
29152  *  
29153  * @return {string} the name of the type of this measurement
29154  */
29155 DigitalStorageUnit.prototype.getMeasure = function() {
29156 	return "digitalStorage";
29157 };
29158 
29159 /**
29160  * Return a new measurement instance that is converted to a new
29161  * measurement unit. Measurements can only be converted
29162  * to measurements of the same type.<p>
29163  *  
29164  * @param {string} to The name of the units to convert to
29165  * @return {Measurement|undefined} the converted measurement
29166  * or undefined if the requested units are for a different
29167  * measurement type
29168  * 
29169  */
29170 DigitalStorageUnit.prototype.convert = function(to) {
29171 	if (!to || typeof(DigitalStorageUnit.ratios[this.normalizeUnits(to)]) === 'undefined') {
29172 		return undefined;
29173 	}
29174 	return new DigitalStorageUnit({
29175 		unit: to,
29176 		amount: this
29177 	});
29178 };
29179 
29180 /**
29181  * Localize the measurement to the commonly used measurement in that locale. For example
29182  * If a user's locale is "en-US" and the measurement is given as "60 kmh", 
29183  * the formatted number should be automatically converted to the most appropriate 
29184  * measure in the other system, in this case, mph. The formatted result should
29185  * appear as "37.3 mph". 
29186  * 
29187  * @param {string} locale current locale string
29188  * @returns {Measurement} a new instance that is converted to locale
29189  */
29190 DigitalStorageUnit.prototype.localize = function(locale) {
29191     return new DigitalStorageUnit({
29192         unit: this.unit,
29193         amount: this.amount
29194     });
29195 };
29196 
29197 /**
29198  * Scale the measurement unit to an acceptable level. The scaling
29199  * happens so that the integer part of the amount is as small as
29200  * possible without being below zero. This will result in the 
29201  * largest units that can represent this measurement without
29202  * fractions. Measurements can only be scaled to other measurements 
29203  * of the same type.
29204  * 
29205  * @param {string=} measurementsystem system to use (uscustomary|imperial|metric),
29206  * or undefined if the system can be inferred from the current measure
29207  * @return {Measurement} a new instance that is scaled to the 
29208  * right level
29209  */
29210 DigitalStorageUnit.prototype.scale = function(measurementsystem) {
29211     var mSystem;
29212     if (this.unit in DigitalStorageUnit.bitSystem) {
29213     	mSystem = DigitalStorageUnit.bitSystem;
29214     } else {
29215     	mSystem = DigitalStorageUnit.byteSystem;
29216     }
29217     
29218     var dStorage = this.amount;
29219     var munit = this.unit;
29220     var fromRow = DigitalStorageUnit.ratios[this.unit];
29221     
29222     dStorage = 18446744073709551999;
29223     for (var m in mSystem) {
29224     	var tmp = this.amount * fromRow[mSystem[m]];
29225         if (tmp >= 1 && tmp < dStorage) {
29226         	dStorage = tmp;
29227 	        munit = m;
29228         }
29229     }
29230     
29231     return new DigitalStorageUnit({
29232 		unit: munit,
29233 		amount: dStorage
29234     });
29235 };
29236 
29237 DigitalStorageUnit.aliases = {
29238     "bits": "bit",
29239     "bit": "bit",
29240     "Bits": "bit",
29241     "Bit": "bit",
29242     "byte": "byte",
29243     "bytes": "byte",
29244     "Byte": "byte",
29245     "Bytes": "byte",
29246     "kilobits": "kilobit",
29247     "Kilobits": "kilobit",
29248     "KiloBits": "kilobit",
29249     "kiloBits": "kilobit",
29250     "kilobit": "kilobit",
29251     "Kilobit": "kilobit",
29252     "kiloBit": "kilobit",
29253     "KiloBit": "kilobit",
29254     "kb": "kilobit",
29255     "Kb": "kilobit",
29256     "kilobyte": "kilobyte",
29257     "Kilobyte": "kilobyte",
29258     "kiloByte": "kilobyte",
29259     "KiloByte": "kilobyte",
29260     "kilobytes": "kilobyte",
29261     "Kilobytes": "kilobyte",
29262     "kiloBytes": "kilobyte",
29263     "KiloBytes": "kilobyte",
29264     "kB": "kilobyte",
29265     "KB": "kilobyte",
29266     "megabit": "megabit",
29267     "Megabit": "megabit",
29268     "megaBit": "megabit",
29269     "MegaBit": "megabit",
29270     "megabits": "megabit",
29271     "Megabits": "megabit",
29272     "megaBits": "megabit",
29273     "MegaBits": "megabit",
29274     "Mb": "megabit",
29275     "mb": "megabit",
29276     "megabyte": "megabyte",
29277     "Megabyte": "megabyte",
29278     "megaByte": "megabyte",
29279     "MegaByte": "megabyte",
29280     "megabytes": "megabyte",
29281     "Megabytes": "megabyte",
29282     "megaBytes": "megabyte",
29283     "MegaBytes": "megabyte",
29284     "MB": "megabyte",
29285     "mB": "megabyte",
29286     "gigabit": "gigabit",
29287     "Gigabit": "gigabit",
29288     "gigaBit": "gigabit",
29289     "GigaBit": "gigabit",
29290     "gigabits": "gigabit",
29291     "Gigabits": "gigabit",
29292     "gigaBits": "gigabyte",
29293     "GigaBits": "gigabit",
29294     "Gb": "gigabit",
29295     "gb": "gigabit",
29296     "gigabyte": "gigabyte",
29297     "Gigabyte": "gigabyte",
29298     "gigaByte": "gigabyte",
29299     "GigaByte": "gigabyte",
29300     "gigabytes": "gigabyte",
29301     "Gigabytes": "gigabyte",
29302     "gigaBytes": "gigabyte",
29303     "GigaBytes": "gigabyte",
29304     "GB": "gigabyte",
29305     "gB": "gigabyte",
29306     "terabit": "terabit",
29307     "Terabit": "terabit",
29308     "teraBit": "terabit",
29309     "TeraBit": "terabit",
29310     "terabits": "terabit",
29311     "Terabits": "terabit",
29312     "teraBits": "terabit",
29313     "TeraBits": "terabit",
29314     "tb": "terabit",
29315     "Tb": "terabit",
29316     "terabyte": "terabyte",
29317     "Terabyte": "terabyte",
29318     "teraByte": "terabyte",
29319     "TeraByte": "terabyte",
29320     "terabytes": "terabyte",
29321     "Terabytes": "terabyte",
29322     "teraBytes": "terabyte",
29323     "TeraBytes": "terabyte",
29324     "TB": "terabyte",
29325     "tB": "terabyte",
29326     "petabit": "petabit",
29327     "Petabit": "petabit",
29328     "petaBit": "petabit",
29329     "PetaBit": "petabit",
29330     "petabits": "petabit",
29331     "Petabits": "petabit",
29332     "petaBits": "petabit",
29333     "PetaBits": "petabit",
29334     "pb": "petabit",
29335     "Pb": "petabit",
29336     "petabyte": "petabyte",
29337     "Petabyte": "petabyte",
29338     "petaByte": "petabyte",
29339     "PetaByte": "petabyte",
29340     "petabytes": "petabyte",
29341     "Petabytes": "petabyte",
29342     "petaBytes": "petabyte",
29343     "PetaBytes": "petabyte",
29344     "PB": "petabyte",
29345     "pB": "petabyte"
29346 };
29347 
29348 /**
29349  * Convert a digitalStorage to another measure.
29350  * @static
29351  * @param to {string} unit to convert to
29352  * @param from {string} unit to convert from
29353  * @param digitalStorage {number} amount to be convert
29354  * @returns {number|undefined} the converted amount
29355  */
29356 DigitalStorageUnit.convert = function(to, from, digitalStorage) {
29357     from = DigitalStorageUnit.aliases[from] || from;
29358     to = DigitalStorageUnit.aliases[to] || to;
29359 	var fromRow = DigitalStorageUnit.ratios[from];
29360 	var toRow = DigitalStorageUnit.ratios[to];
29361 	if (typeof(from) === 'undefined' || typeof(to) === 'undefined') {
29362 		return undefined;
29363 	}	
29364 	var result = digitalStorage * fromRow[toRow[0]];
29365     return result;
29366 };
29367 
29368 /**
29369  * @private
29370  * @static
29371  */
29372 DigitalStorageUnit.getMeasures = function () {
29373 	var ret = [];
29374 	for (var m in DigitalStorageUnit.ratios) {
29375 		ret.push(m);
29376 	}
29377 	return ret;
29378 };
29379 
29380 //register with the factory method
29381 Measurement._constructors["digitalStorage"] = DigitalStorageUnit;
29382 
29383 
29384 /*< EnergyUnit.js */
29385 /*
29386  * Energy.js - Unit conversions for Energys/energys
29387  *
29388  * Copyright © 2014-2015, JEDLSoft
29389  *
29390  * Licensed under the Apache License, Version 2.0 (the "License");
29391  * you may not use this file except in compliance with the License.
29392  * You may obtain a copy of the License at
29393  *
29394  *     http://www.apache.org/licenses/LICENSE-2.0
29395  *
29396  * Unless required by applicable law or agreed to in writing, software
29397  * distributed under the License is distributed on an "AS IS" BASIS,
29398  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29399  *
29400  * See the License for the specific language governing permissions and
29401  * limitations under the License.
29402  */
29403 
29404 /*
29405 !depends
29406 Measurement.js
29407 */
29408 
29409 
29410 /**
29411  * @class
29412  * Create a new energy measurement instance.
29413  * 
29414  * @constructor
29415  * @extends Measurement
29416  * @param options {{unit:string,amount:number|string|undefined}} Options controlling
29417  * the construction of this instance
29418  */
29419 var EnergyUnit = function (options) {
29420 	this.unit = "joule";
29421 	this.amount = 0;
29422 	this.aliases = EnergyUnit.aliases; // share this table in all instances
29423 
29424 	if (options) {
29425 		if (typeof(options.unit) !== 'undefined') {
29426 			this.originalUnit = options.unit;
29427 			this.unit = this.aliases[options.unit] || options.unit;
29428 		}
29429 
29430 		if (typeof(options.amount) === 'object') {
29431 			if (options.amount.getMeasure() === "energy") {
29432 				this.amount = EnergyUnit.convert(this.unit, options.amount.getUnit(), options.amount.getAmount());
29433 			} else {
29434 				throw "Cannot convert units " + options.amount.unit + " to a energy";
29435 			}
29436 		} else if (typeof(options.amount) !== 'undefined') {
29437 			this.amount = parseFloat(options.amount);
29438 		}
29439 	}
29440 
29441 	if (typeof(EnergyUnit.ratios[this.unit]) === 'undefined') {
29442 		throw "Unknown unit: " + options.unit;
29443 	}
29444 };
29445 
29446 EnergyUnit.prototype = new Measurement();
29447 EnergyUnit.prototype.parent = Measurement;
29448 EnergyUnit.prototype.constructor = EnergyUnit;
29449 
29450 EnergyUnit.ratios = {
29451    /*                index mJ          J           BTU               kJ          Wh                Cal               MJ             kWh                gJ             MWh                 GWh         */
29452     "millijoule":   [ 1,   1,          0.001,      9.4781707775e-7,  1e-6,       2.7777777778e-7,  2.3884589663e-7,  1.0e-9,        2.7777777778e-10,  1.0e-12,       2.7777777778e-13,   2.7777777778e-16  ],
29453     "joule":        [ 2,   1000,       1,          9.4781707775e-4,  0.001,      2.7777777778e-4,  2.3884589663e-4,  1.0e-6,        2.7777777778e-7,   1.0e-9,        2.7777777778e-10,   2.7777777778e-13  ],
29454     "BTU":          [ 3,   1055055.9,  1055.0559,  1,                1.0550559,  0.29307108333,    0.25199577243,    1.0550559e-3,  2.9307108333e-4,   1.0550559e-6,  2.9307108333e-7,    2.9307108333e-10  ],
29455     "kilojoule":    [ 4,   1000000,    1000,       0.94781707775,    1,          0.27777777778,    0.23884589663,    0.001,         2.7777777778e-4,   1.0e-6,        2.7777777778e-7,    2.7777777778e-10  ],
29456     "watt hour":    [ 5,   3.6e+6,     3600,       3.4121414799,     3.6,        1,                0.85984522786,    0.0036,        0.001,             3.6e-6,        1.0e-6,             1.0e-9            ],
29457     "calorie":      [ 6,   4.868e+5,   4186.8,     3.9683205411,     4.1868,     1.163,            1,                4.1868e-3,     1.163e-3,          4.1868e-6,     1.163e-6,           1.163e-9          ],
29458     "megajoule":    [ 7,   1e+9,       1e+6,       947.81707775,     1000,       277.77777778,     238.84589663,     1,             0.27777777778,     0.001,         2.7777777778e-4,    2.7777777778e-7   ],
29459     "kilowatt hour":[ 8,   3.6e+9,     3.6e+6,     3412.1414799,     3600,       1000,             859.84522786,     3.6,           1,                 3.6e-3,        0.001,              1e-6              ],
29460     "gigajoule":    [ 9,   1e+12,      1e+9,       947817.07775,     1e+6,       277777.77778,     238845.89663,     1000,          277.77777778,      1,             0.27777777778,      2.7777777778e-4   ],
29461     "megawatt hour":[ 10,  3.6e+12,    3.6e+9,     3412141.4799,     3.6e+6,     1e+6,             859845.22786,     3600,          1000,              3.6,           1,                  0.001             ],
29462     "gigawatt hour":[ 11,  3.6e+15,    3.6e+12,    3412141479.9,     3.6e+9,     1e+9,             859845227.86,     3.6e+6,        1e+6,              3600,          1000,               1                 ]
29463 };
29464 
29465 /**
29466  * Return the type of this measurement. Examples are "mass",
29467  * "length", "speed", etc. Measurements can only be converted
29468  * to measurements of the same type.<p>
29469  * 
29470  * The type of the units is determined automatically from the 
29471  * units. For example, the unit "grams" is type "mass". Use the 
29472  * static call {@link Measurement.getAvailableUnits}
29473  * to find out what units this version of ilib supports.
29474  *  
29475  * @return {string} the name of the type of this measurement
29476  */
29477 EnergyUnit.prototype.getMeasure = function() {
29478 	return "energy";
29479 };
29480 
29481 /**
29482  * Return a new measurement instance that is converted to a new
29483  * measurement unit. Measurements can only be converted
29484  * to measurements of the same type.<p>
29485  *  
29486  * @param {string} to The name of the units to convert to
29487  * @return {Measurement|undefined} the converted measurement
29488  * or undefined if the requested units are for a different
29489  * measurement type 
29490  */
29491 EnergyUnit.prototype.convert = function(to) {
29492 	if (!to || typeof(EnergyUnit.ratios[this.normalizeUnits(to)]) === 'undefined') {
29493 		return undefined;
29494 	}
29495 	return new EnergyUnit({
29496 		unit: to,
29497 		amount: this
29498 	});
29499 };
29500 
29501 EnergyUnit.aliases = {
29502     "milli joule": "millijoule",
29503     "millijoule": "millijoule",
29504     "MilliJoule": "millijoule",
29505     "milliJ": "millijoule",
29506     "joule": "joule",
29507     "J": "joule",
29508     "j": "joule",
29509     "Joule": "joule",
29510     "Joules": "joule",
29511     "joules": "joule",
29512     "BTU": "BTU",
29513     "btu": "BTU",
29514     "British thermal unit": "BTU",
29515     "british thermal unit": "BTU",
29516     "kilo joule": "kilojoule",
29517     "kJ": "kilojoule",
29518     "kj": "kilojoule",
29519     "Kj": "kilojoule",
29520     "kiloJoule": "kilojoule",
29521     "kilojoule": "kilojoule",
29522     "kjoule": "kilojoule",
29523     "watt hour": "watt hour",
29524     "Wh": "watt hour",
29525     "wh": "watt hour",
29526     "watt-hour": "watt hour",
29527     "calorie": "calorie",
29528     "Cal": "calorie",
29529     "cal": "calorie",
29530     "Calorie": "calorie",
29531     "calories": "calorie",
29532     "mega joule": "megajoule",
29533     "MJ": "megajoule",
29534     "megajoule": "megajoule",
29535     "megajoules": "megajoule",
29536     "Megajoules": "megajoule",
29537     "megaJoules": "megajoule",
29538     "MegaJoules": "megajoule",
29539     "megaJoule": "megajoule",
29540     "MegaJoule": "megajoule",
29541     "kilo Watt hour": "kilowatt hour",
29542     "kWh": "kilowatt hour",
29543     "kiloWh": "kilowatt hour",
29544     "KiloWh": "kilowatt hour",
29545     "KiloWatt-hour": "kilowatt hour",
29546     "kilowatt hour": "kilowatt hour",
29547     "kilowatt-hour": "kilowatt hour",
29548     "KiloWatt-hours": "kilowatt hour",
29549     "kilowatt-hours": "kilowatt hour",
29550     "Kilo Watt-hour": "kilowatt hour",
29551     "Kilo Watt-hours": "kilowatt hour",
29552     "giga joule": "gigajoule",
29553     "gJ": "gigajoule",
29554     "GJ": "gigajoule",
29555     "GigaJoule": "gigajoule",
29556     "gigaJoule": "gigajoule",
29557     "gigajoule": "gigajoule",   
29558     "GigaJoules": "gigajoule",
29559     "gigaJoules": "gigajoule",
29560     "Gigajoules": "gigajoule",
29561     "gigajoules": "gigajoule",
29562     "mega watt hour": "megawatt hour",
29563     "MWh": "megawatt hour",
29564     "MegaWh": "megawatt hour",
29565     "megaWh": "megawatt hour",
29566     "megaWatthour": "megawatt hour",
29567     "megaWatt-hour": "megawatt hour",
29568     "mega Watt-hour": "megawatt hour",
29569     "megaWatt hour": "megawatt hour",
29570     "megawatt hour": "megawatt hour",
29571     "mega Watt hour": "megawatt hour",
29572     "giga watt hour": "gigawatt hour",
29573     "gWh": "gigawatt hour",
29574     "GWh": "gigawatt hour",
29575     "gigaWh": "gigawatt hour",
29576     "gigaWatt-hour": "gigawatt hour",
29577     "gigawatt-hour": "gigawatt hour",
29578     "gigaWatt hour": "gigawatt hour",
29579     "gigawatt hour": "gigawatt hour",
29580     "gigawatthour": "gigawatt hour"
29581 };
29582 
29583 /**
29584  * Convert a energy to another measure.
29585  * @static
29586  * @param to {string} unit to convert to
29587  * @param from {string} unit to convert from
29588  * @param energy {number} amount to be convert
29589  * @returns {number|undefined} the converted amount
29590  */
29591 EnergyUnit.convert = function(to, from, energy) {
29592     from = EnergyUnit.aliases[from] || from;
29593     to = EnergyUnit.aliases[to] || to;
29594     var fromRow = EnergyUnit.ratios[from];
29595     var toRow = EnergyUnit.ratios[to];
29596     if (typeof(from) === 'undefined' || typeof(to) === 'undefined') {
29597         return undefined;
29598     }
29599     return energy * fromRow[toRow[0]];
29600 };
29601 
29602 /**
29603  * @private
29604  * @static
29605  */
29606 EnergyUnit.getMeasures = function () {
29607 	var ret = [];
29608 	for (var m in EnergyUnit.ratios) {
29609 		ret.push(m);
29610 	}
29611 	return ret;
29612 };
29613 
29614 EnergyUnit.metricJouleSystem = {
29615     "millijoule": 1,
29616     "joule": 2,
29617     "kilojoule": 4,
29618     "megajoule": 7,
29619     "gigajoule": 9
29620 };
29621 EnergyUnit.metricWattHourSystem = {
29622     "watt hour": 5,
29623     "kilowatt hour": 8,
29624     "megawatt hour": 10,
29625     "gigawatt hour": 11
29626 };
29627 
29628 EnergyUnit.imperialSystem = {
29629 	"BTU": 3
29630 };
29631 EnergyUnit.uscustomarySystem = {
29632 	"calorie": 6
29633 };
29634 
29635 EnergyUnit.metricToImperial = {
29636     "millijoule": "BTU",
29637     "joule": "BTU",
29638     "kilojoule": "BTU",
29639     "megajoule": "BTU",
29640     "gigajoule": "BTU"
29641 };
29642 EnergyUnit.imperialToMetric = {
29643 	"BTU": "joule"
29644 };
29645 
29646 /**
29647  * Localize the measurement to the commonly used measurement in that locale. For example
29648  * If a user's locale is "en-US" and the measurement is given as "60 kmh", 
29649  * the formatted number should be automatically converted to the most appropriate 
29650  * measure in the other system, in this case, mph. The formatted result should
29651  * appear as "37.3 mph". 
29652  * 
29653  * @param {string} locale current locale string
29654  * @returns {Measurement} a new instance that is converted to locale
29655  */
29656 EnergyUnit.prototype.localize = function(locale) {
29657 	var to;
29658 	if (locale === "en-GB") {
29659 		to = EnergyUnit.metricToImperial[this.unit] || this.unit;
29660 	} else {
29661 		to = EnergyUnit.imperialToMetric[this.unit] || this.unit;
29662 	}
29663 
29664 	return new EnergyUnit({
29665 	    unit: to,
29666 	    amount: this
29667 	});
29668 };
29669 
29670 /**
29671  * Scale the measurement unit to an acceptable level. The scaling
29672  * happens so that the integer part of the amount is as small as
29673  * possible without being below zero. This will result in the 
29674  * largest units that can represent this measurement without
29675  * fractions. Measurements can only be scaled to other measurements 
29676  * of the same type.
29677  * 
29678  * @param {string=} measurementsystem system to use (uscustomary|imperial|metric),
29679  * or undefined if the system can be inferred from the current measure
29680  * @return {Measurement} a new instance that is scaled to the 
29681  * right level
29682  */
29683 EnergyUnit.prototype.scale = function(measurementsystem) {
29684     var fromRow = EnergyUnit.ratios[this.unit];
29685     var mSystem;
29686 
29687     if ((measurementsystem === "metric" && typeof(EnergyUnit.metricJouleSystem[this.unit]) !== 'undefined')|| (typeof(measurementsystem) === 'undefined'
29688         && typeof(EnergyUnit.metricJouleSystem[this.unit]) !== 'undefined')) {
29689         mSystem = EnergyUnit.metricJouleSystem;
29690     }
29691     else if ((measurementsystem === "metric" && typeof(EnergyUnit.metricWattHourSystem[this.unit]) !== 'undefined')|| (typeof(measurementsystem) === 'undefined'
29692         && typeof(EnergyUnit.metricWattHourSystem[this.unit]) !== 'undefined')) {
29693         mSystem = EnergyUnit.metricWattHourSystem;
29694     }
29695 
29696     else  if (measurementsystem === "uscustomary" || (typeof(measurementsystem) === 'undefined'
29697         && typeof(EnergyUnit.uscustomarySystem[this.unit]) !== 'undefined')) {
29698         mSystem = EnergyUnit.uscustomarySystem;
29699     }
29700     else if (measurementsystem === "imperial"|| (typeof(measurementsystem) === 'undefined'
29701         && typeof(EnergyUnit.imperialSystem[this.unit]) !== 'undefined')) {
29702         mSystem = EnergyUnit.imperialSystem;
29703     }
29704 
29705     var energy = this.amount;
29706     var munit = this.unit;
29707 
29708     energy = 18446744073709551999;
29709     
29710     for (var m in mSystem) {
29711         var tmp = this.amount * fromRow[mSystem[m]];
29712         if (tmp >= 1 && tmp < energy) {
29713 	        energy = tmp;
29714 	        munit = m;
29715         }
29716     }
29717 
29718     return new EnergyUnit({
29719         unit: munit,
29720         amount: energy
29721     });
29722 };
29723 //register with the factory method
29724 Measurement._constructors["energy"] = EnergyUnit;
29725 
29726 
29727 /*< FuelConsumptionUnit.js */
29728 /*
29729  * fuelconsumption.js - Unit conversions for FuelConsumption
29730  *
29731  * Copyright © 2014-2015, JEDLSoft
29732  *
29733  * Licensed under the Apache License, Version 2.0 (the "License");
29734  * you may not use this file except in compliance with the License.
29735  * You may obtain a copy of the License at
29736  *
29737  *     http://www.apache.org/licenses/LICENSE-2.0
29738  *
29739  * Unless required by applicable law or agreed to in writing, software
29740  * distributed under the License is distributed on an "AS IS" BASIS,
29741  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29742  *
29743  * See the License for the specific language governing permissions and
29744  * limitations under the License.
29745  */
29746 
29747 /*
29748 !depends 
29749 Measurement.js 
29750 */
29751 
29752 
29753 /**
29754  * @class
29755  * Create a new fuelconsumption measurement instance.
29756  * 
29757  * @constructor
29758  * @extends Measurement
29759  * @param options {{unit:string,amount:number|string|undefined}} Options controlling
29760  * the construction of this instance
29761  */
29762 var FuelConsumptionUnit = function(options) {
29763     this.unit = "km/liter";
29764     this.amount = 0;
29765     this.aliases = FuelConsumptionUnit.aliases; // share this table in all instances
29766 
29767     if (options) {
29768         if (typeof(options.unit) !== 'undefined') {
29769             this.originalUnit = options.unit;
29770             this.unit = this.aliases[options.unit] || options.unit;
29771         }
29772 
29773         if (typeof(options.amount) === 'object') {
29774             if (options.amount.getMeasure() === "fuelconsumption") {
29775                 this.amount = FuelConsumptionUnit.convert(this.unit, options.amount.getUnit(), options.amount.getAmount());
29776             } else {
29777                 throw "Cannot convert unit " + options.amount.unit + " to fuelconsumption";
29778             }
29779         } else if (typeof(options.amount) !== 'undefined') {
29780             this.amount = parseFloat(options.amount);
29781         }
29782     }
29783 };
29784 
29785 FuelConsumptionUnit.prototype = new Measurement();
29786 FuelConsumptionUnit.prototype.parent = Measurement;
29787 FuelConsumptionUnit.prototype.constructor = FuelConsumptionUnit;
29788 
29789 FuelConsumptionUnit.ratios = [
29790     "km/liter",
29791     "liter/100km",
29792     "mpg",
29793     "mpg(imp)"
29794 ];
29795 
29796 /**
29797  * Return the type of this measurement. Examples are "mass",
29798  * "length", "speed", etc. Measurements can only be converted
29799  * to measurements of the same type.<p>
29800  * 
29801  * The type of the units is determined automatically from the 
29802  * units. For example, the unit "grams" is type "mass". Use the 
29803  * static call {@link Measurement.getAvailableUnits}
29804  * to find out what units this version of ilib supports.
29805  *  
29806  * @return {string} the name of the type of this measurement
29807  */
29808 FuelConsumptionUnit.prototype.getMeasure = function() {
29809     return "fuelconsumption";
29810 };
29811 
29812 /**
29813  * Return a new measurement instance that is converted to a new
29814  * measurement unit. Measurements can only be converted
29815  * to measurements of the same type.<p>
29816  *  
29817  * @param {string} to The name of the units to convert to
29818  * @return {Measurement|undefined} the converted measurement
29819  * or undefined if the requested units are for a different
29820  * measurement type 
29821  */
29822 FuelConsumptionUnit.prototype.convert = function(to) {
29823     if (!to || typeof(FuelConsumptionUnit.ratios[this.normalizeUnits(to)]) === 'undefined') {
29824         return undefined;
29825     }
29826     return new FuelConsumptionUnit({
29827         unit: to,
29828         amount: this
29829     });
29830 };
29831 /*["km/liter", "liter/100km", "mpg", "mpg(imp)"*/
29832 FuelConsumptionUnit.aliases = {
29833     "Km/liter": "km/liter",
29834     "KM/Liter": "km/liter",
29835     "KM/L": "km/liter",
29836     "Kilometers Per Liter": "km/liter",
29837     "kilometers per liter": "km/liter",
29838     "km/l": "km/liter",
29839     "Kilometers/Liter": "km/liter",
29840     "Kilometer/Liter": "km/liter",
29841     "kilometers/liter": "km/liter",
29842     "kilometer/liter": "km/liter",
29843     "km/liter": "km/liter",
29844     "Liter/100km": "liter/100km",
29845     "Liters/100km": "liter/100km",
29846     "Liter/100kms": "liter/100km",
29847     "Liters/100kms": "liter/100km",
29848     "liter/100km": "liter/100km",
29849     "liters/100kms": "liter/100km",
29850     "liters/100km": "liter/100km",
29851     "liter/100kms": "liter/100km",
29852     "Liter/100KM": "liter/100km",
29853     "Liters/100KM": "liter/100km",
29854     "L/100km": "liter/100km",
29855     "L/100KM": "liter/100km",
29856     "l/100KM": "liter/100km",
29857     "l/100km": "liter/100km",
29858     "l/100kms": "liter/100km",
29859     "MPG(US)": "mpg",
29860     "USMPG ": "mpg",
29861     "mpg": "mpg",
29862     "mpgUS": "mpg",
29863     "mpg(US)": "mpg",
29864     "mpg(us)": "mpg",
29865     "mpg-us": "mpg",
29866     "mpg Imp": "mpg(imp)",
29867     "MPG(imp)": "mpg(imp)",
29868     "mpg(imp)": "mpg(imp)",
29869     "mpg-imp": "mpg(imp)"
29870 };
29871 
29872 FuelConsumptionUnit.metricToUScustomary = {
29873     "km/liter": "mpg",
29874     "liter/100km": "mpg"
29875 };
29876 FuelConsumptionUnit.metricToImperial = {
29877     "km/liter": "mpg(imp)",
29878     "liter/100km": "mpg(imp)"
29879 };
29880 
29881 FuelConsumptionUnit.imperialToMetric = {
29882 	"mpg(imp)": "km/liter"
29883 };
29884 FuelConsumptionUnit.imperialToUScustomary = {
29885 	"mpg(imp)": "mpg"
29886 };
29887 
29888 FuelConsumptionUnit.uScustomaryToImperial = {
29889 	"mpg": "mpg(imp)"
29890 };
29891 FuelConsumptionUnit.uScustomarylToMetric = {
29892 	"mpg": "km/liter"
29893 };
29894 
29895 /**
29896  * Localize the measurement to the commonly used measurement in that locale. For example
29897  * If a user's locale is "en-US" and the measurement is given as "60 kmh", 
29898  * the formatted number should be automatically converted to the most appropriate 
29899  * measure in the other system, in this case, mph. The formatted result should
29900  * appear as "37.3 mph". 
29901  * 
29902  * @param {string} locale current locale string
29903  * @returns {Measurement} a new instance that is converted to locale
29904  */
29905 FuelConsumptionUnit.prototype.localize = function(locale) {
29906 	var to;
29907 	if (locale === "en-US") {
29908 		to = FuelConsumptionUnit.metricToUScustomary[this.unit] ||
29909 		    FuelConsumptionUnit.imperialToUScustomary[this.unit] ||
29910 		    this.unit;
29911 	} else if (locale === "en-GB") {
29912 		to = FuelConsumptionUnit.metricToImperial[this.unit] ||
29913 		    FuelConsumptionUnit.uScustomaryToImperial[this.unit] ||
29914 		    this.unit;
29915 	} else {
29916 		to = FuelConsumptionUnit.uScustomarylToMetric[this.unit] ||
29917 		    FuelConsumptionUnit.imperialToUScustomary[this.unit] ||
29918 		    this.unit;
29919 	}
29920 	return new FuelConsumptionUnit({
29921 	    unit: to,
29922 	    amount: this
29923 	});
29924 };
29925 
29926 /**
29927  * Convert a FuelConsumption to another measure.
29928  * 
29929  * @static
29930  * @param to {string} unit to convert to
29931  * @param from {string} unit to convert from
29932  * @param fuelConsumption {number} amount to be convert
29933  * @returns {number|undefined} the converted amount
29934  */
29935 FuelConsumptionUnit.convert = function(to, from, fuelConsumption) {
29936     from = FuelConsumptionUnit.aliases[from] || from;
29937     to = FuelConsumptionUnit.aliases[to] || to;
29938     var returnValue = 0;
29939 
29940     switch (from) {
29941         case "km/liter":
29942             switch (to) {
29943                 case "km/liter":
29944                     returnValue = fuelConsumption * 1;
29945                     break;
29946                 case "liter/100km":
29947                     returnValue = 100 / fuelConsumption;
29948                     break;
29949                 case "mpg":
29950                     returnValue = fuelConsumption * 2.35215;
29951                     break;
29952                 case "mpg(imp)":
29953                     returnValue = fuelConsumption * 2.82481;
29954                     break;
29955             }
29956             break;
29957         case "liter/100km":
29958             switch (to) {
29959                 case "km/liter":
29960                     returnValue = 100 / fuelConsumption;
29961                     break;
29962                 case "liter/100km":
29963                     returnValue = fuelConsumption * 1;
29964                     break;
29965                 case "mpg":
29966                     returnValue = 235.215 / fuelConsumption;
29967                     break;
29968                 case "mpg(imp)":
29969                     returnValue = 282.481 / fuelConsumption;
29970                     break;
29971             }
29972             break;
29973         case "mpg":
29974             switch (to) {
29975                 case "km/liter":
29976                     returnValue = fuelConsumption * 0.425144;
29977                     break;
29978                 case "liter/100km":
29979                     returnValue = 235.215 / fuelConsumption;
29980                     break;
29981                 case "mpg":
29982                     returnValue = 1 * fuelConsumption;
29983                     break;
29984                 case "mpg(imp)":
29985                     returnValue = 1.20095 * fuelConsumption;
29986                     break;
29987             }
29988             break;
29989         case "mpg(imp)":
29990             switch (to) {
29991                 case "km/liter":
29992                     returnValue = fuelConsumption * 0.354006;
29993                     break;
29994                 case "liter/100km":
29995                     returnValue = 282.481 / fuelConsumption;
29996                     break;
29997                 case "mpg":
29998                     returnValue = 0.832674 * fuelConsumption;
29999                     break;
30000                 case "mpg(imp)":
30001                     returnValue = 1 * fuelConsumption;
30002                     break;
30003             }
30004             break;
30005     }
30006     return returnValue;
30007 };
30008 
30009 /**
30010  * Scale the measurement unit to an acceptable level. The scaling
30011  * happens so that the integer part of the amount is as small as
30012  * possible without being below zero. This will result in the 
30013  * largest units that can represent this measurement without
30014  * fractions. Measurements can only be scaled to other measurements 
30015  * of the same type.
30016  * 
30017  * @param {string=} measurementsystem system to use (uscustomary|imperial|metric),
30018  * or undefined if the system can be inferred from the current measure
30019  * @return {Measurement} a new instance that is scaled to the 
30020  * right level
30021  */
30022 FuelConsumptionUnit.prototype.scale = function(measurementsystem) {
30023     return new FuelConsumptionUnit({
30024         unit: this.unit,
30025         amount: this.amount
30026     }); 
30027 };
30028 
30029 /**
30030  * @private
30031  * @static
30032  */
30033 FuelConsumptionUnit.getMeasures = function() {
30034     var ret = [];
30035     ret.push("km/liter");
30036     ret.push("liter/100km");
30037     ret.push("mpg");
30038     ret.push("mpg(imp)");
30039     
30040     return ret;
30041 };
30042 
30043 //register with the factory method
30044 Measurement._constructors["fuelconsumption"] = FuelConsumptionUnit;
30045 
30046 
30047 /*< LengthUnit.js */
30048 /*
30049  * LengthUnit.js - Unit conversions for Lengths/lengths
30050  * 
30051  * Copyright © 2014-2015, JEDLSoft
30052  *
30053  * Licensed under the Apache License, Version 2.0 (the "License");
30054  * you may not use this file except in compliance with the License.
30055  * You may obtain a copy of the License at
30056  *
30057  *     http://www.apache.org/licenses/LICENSE-2.0
30058  *
30059  * Unless required by applicable law or agreed to in writing, software
30060  * distributed under the License is distributed on an "AS IS" BASIS,
30061  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
30062  *
30063  * See the License for the specific language governing permissions and
30064  * limitations under the License.
30065  */
30066 
30067 /*
30068 !depends 
30069 Measurement.js
30070 */
30071 
30072 
30073 /**
30074  * @class
30075  * Create a new length measurement instance.
30076  *  
30077  * @constructor
30078  * @extends Measurement
30079  * @param options {{unit:string,amount:number|string|undefined}} Options controlling 
30080  * the construction of this instance
30081  */
30082 var LengthUnit = function (options) {
30083 	this.unit = "meter";
30084 	this.amount = 0;
30085 	this.aliases = LengthUnit.aliases; // share this table in all instances
30086 	
30087 	if (options) {
30088 		if (typeof(options.unit) !== 'undefined') {
30089 			this.originalUnit = options.unit;
30090 			this.unit = this.aliases[options.unit] || options.unit;
30091 		}
30092 		
30093 		if (typeof(options.amount) === 'object') {
30094 			if (options.amount.getMeasure() === "length") {
30095 				this.amount = LengthUnit.convert(this.unit, options.amount.getUnit(), options.amount.getAmount());
30096 			} else {
30097 				throw "Cannot convert unit " + options.amount.unit + " to a length";
30098 			}
30099 		} else if (typeof(options.amount) !== 'undefined') {
30100 			this.amount = parseFloat(options.amount);
30101 		}
30102 	}
30103 	
30104 	if (typeof(LengthUnit.ratios[this.unit]) === 'undefined') {
30105 		throw "Unknown unit: " + options.unit;
30106 	}
30107 };
30108 
30109 LengthUnit.prototype = new Measurement();
30110 LengthUnit.prototype.parent = Measurement;
30111 LengthUnit.prototype.constructor = LengthUnit;
30112 
30113 LengthUnit.ratios = {
30114 	/*              index, µm           mm           cm           inch         dm           foot          yard          m             dam            hm              km              mile            nm            Mm             Gm             */ 
30115 	"micrometer":   [ 1,   1,           1e-3,        1e-4,        3.93701e-5,  1e-5,        3.28084e-6,   1.09361e-6,   1e-6,         1e-7,          1e-8,           1e-9,           6.21373e-10,  5.39957e-10,  1e-12,          1e-15           ],
30116 	"millimeter":   [ 2,   1000,        1,           0.1,         0.0393701,   0.01,        0.00328084,   1.09361e-3,   0.001,        1e-4,          1e-5,           1e-6,           6.21373e-7,   5.39957e-7,   1e-9,           1e-12           ],
30117 	"centimeter":   [ 3,   1e4,         10,          1,           0.393701,    0.1,         0.0328084,    0.0109361,    0.01,         0.001,         1e-4,           1e-5,           6.21373e-6,   5.39957e-6,   1e-8,           1e-9            ],
30118     "inch":         [ 4,   25399.986,   25.399986,   2.5399986,   1,           0.25399986,  0.083333333,  0.027777778,  0.025399986,  2.5399986e-3,  2.5399986e-4,   2.5399986e-5,   1.5783e-5,    1.3715e-5,    2.5399986e-8,   2.5399986e-11   ],
30119     "decimeter":    [ 5,   1e5,         100,         10,          3.93701,     1,           0.328084,     0.109361,     0.1,          0.01,          0.001,          1e-4,           6.21373e-5,   5.39957e-5,   1e-7,           1e-8            ],
30120     "foot":         [ 6,   304799.99,   304.79999,   30.479999,   12,          3.0479999,   1,            0.33333333,   0.30479999,   0.030479999,   3.0479999e-3,   3.0479999e-4,   1.89394e-4,   1.64579e-4,   3.0479999e-7,   3.0479999e-10   ],
30121     "yard":         [ 7,   914402.758,  914.402758,  91.4402758,  36,          9.14402758,  3,            1,            0.914402758,  0.0914402758,  9.14402758e-3,  9.14402758e-4,  5.68182e-4,   4.93737e-4,   9.14402758e-7,  9.14402758e-10  ],
30122 	"meter":        [ 8,   1e6,         1000,        100,         39.3701,     10,          3.28084,      1.09361,      1,            0.1,           0.01,           0.001,          6.213712e-4,  5.39957e-4,   1e-6,           1e-7            ],
30123 	"decameter":    [ 9,   1e7,         1e4,         1000,        393.701,     100,         32.8084,      10.9361,      10,           1,             0.1,            0.01,           6.21373e-3,   5.39957e-3,   1e-5,           1e-6            ],
30124 	"hectometer":   [ 10,  1e8,         1e5,         1e4,         3937.01,     1000,        328.084,      109.361,      100,          10,            1,              0.1,            0.0621373,    0.0539957,    1e-4,           1e-5            ],
30125 	"kilometer":    [ 11,  1e9,         1e6,         1e5,         39370.1,     1e4,         3280.84,      1093.61,      1000,         100,           10,             1,              0.621373,     0.539957,     0.001,          1e-4            ],
30126     "mile":         [ 12,  1.60934e9,   1.60934e6,   1.60934e5,   63360,       1.60934e4,   5280,         1760,         1609.34,      160.934,       16.0934,        1.60934,        1,            0.868976,     1.60934e-3,     1.60934e-6      ],
30127     "nauticalmile": [ 13,  1.852e9,     1.852e6,     1.852e5,     72913.4,     1.852e4,     6076.12,      2025.37,      1852,         185.2,         18.52,          1.852,          1.15078,      1,            1.852e-3,       1.852e-6        ],
30128 	"megameter":    [ 14,  1e12,        1e9,         1e6,         3.93701e7,   1e5,         3.28084e6,    1.09361e6,    1e4,          1000,          100,            10,             621.373,      539.957,      1,              0.001           ],        
30129     "gigameter":    [ 15,  1e15,        1e12,        1e9,         3.93701e10,  1e8,         3.28084e9,    1.09361e9,    1e7,          1e6,           1e5,            1e4,            621373.0,     539957.0,     1000,           1               ]	
30130 };
30131 
30132 LengthUnit.metricSystem = {
30133     "micrometer": 1,
30134     "millimeter": 2,
30135     "centimeter": 3,
30136     "decimeter": 5,
30137     "meter": 8,
30138     "decameter": 9,
30139     "hectometer": 10,
30140     "kilometer": 11,
30141     "megameter": 14,
30142     "gigameter": 15
30143 };
30144 LengthUnit.imperialSystem = {
30145     "inch": 4,
30146     "foot": 6,
30147     "yard": 7,
30148     "mile": 12,
30149     "nauticalmile": 13
30150 };
30151 LengthUnit.uscustomarySystem = {
30152     "inch": 4,
30153     "foot": 6,
30154     "yard": 7,
30155     "mile": 12,
30156     "nauticalmile": 13
30157 };
30158 
30159 LengthUnit.metricToUScustomary = {
30160     "micrometer": "inch",
30161     "millimeter": "inch",
30162     "centimeter": "inch",
30163     "decimeter": "inch",
30164     "meter": "yard",
30165     "decameter": "yard",
30166     "hectometer": "mile",
30167     "kilometer": "mile",
30168     "megameter": "nauticalmile",
30169     "gigameter": "nauticalmile"
30170 };
30171 LengthUnit.usCustomaryToMetric = {
30172     "inch": "centimeter",
30173     "foot": "centimeter",
30174     "yard": "meter",
30175     "mile": "kilometer",
30176     "nauticalmile": "kilometer"
30177 };
30178 
30179 /**
30180  * Return the type of this measurement. Examples are "mass",
30181  * "length", "speed", etc. Measurements can only be converted
30182  * to measurements of the same type.<p>
30183  * 
30184  * The type of the units is determined automatically from the 
30185  * units. For example, the unit "grams" is type "mass". Use the 
30186  * static call {@link Measurement.getAvailableUnits}
30187  * to find out what units this version of ilib supports.
30188  *  
30189  * @return {string} the name of the type of this measurement
30190  */
30191 LengthUnit.prototype.getMeasure = function() {
30192 	return "length";
30193 };
30194 
30195 /**
30196  * Localize the measurement to the commonly used measurement in that locale. For example
30197  * If a user's locale is "en-US" and the measurement is given as "60 kmh", 
30198  * the formatted number should be automatically converted to the most appropriate 
30199  * measure in the other system, in this case, mph. The formatted result should
30200  * appear as "37.3 mph". 
30201  * 
30202  * @param {string} locale current locale string
30203  * @returns {Measurement} a new instance that is converted to locale
30204  */
30205 LengthUnit.prototype.localize = function(locale) {
30206     var to;
30207     if (locale === "en-US" || locale === "en-GB") {
30208         to = LengthUnit.metricToUScustomary[this.unit] || this.unit;
30209     } else {
30210         to = LengthUnit.usCustomaryToMetric[this.unit] || this.unit;
30211     }
30212     return new LengthUnit({
30213         unit: to,
30214         amount: this
30215     });
30216 };
30217 
30218 /**
30219  * Return a new measurement instance that is converted to a new
30220  * measurement unit. Measurements can only be converted
30221  * to measurements of the same type.<p>
30222  *  
30223  * @param {string} to The name of the units to convert to
30224  * @return {Measurement|undefined} the converted measurement
30225  * or undefined if the requested units are for a different
30226  * measurement type 
30227  */
30228 LengthUnit.prototype.convert = function(to) {
30229 	if (!to || typeof(LengthUnit.ratios[this.normalizeUnits(to)]) === 'undefined') {
30230 		return undefined;
30231 	}
30232 	return new LengthUnit({
30233 		unit: to,
30234 		amount: this
30235 	});
30236 };
30237 
30238 /**
30239  * Scale the measurement unit to an acceptable level. The scaling
30240  * happens so that the integer part of the amount is as small as
30241  * possible without being below zero. This will result in the 
30242  * largest units that can represent this measurement without
30243  * fractions. Measurements can only be scaled to other measurements 
30244  * of the same type.
30245  * 
30246  * @param {string=} measurementsystem system to use (uscustomary|imperial|metric),
30247  * or undefined if the system can be inferred from the current measure
30248  * @return {Measurement} a new instance that is scaled to the 
30249  * right level
30250  */
30251 LengthUnit.prototype.scale = function(measurementsystem) {
30252     var mSystem;    
30253     if (measurementsystem === "metric" || (typeof(measurementsystem) === 'undefined' 
30254             && typeof(LengthUnit.metricSystem[this.unit]) !== 'undefined')) {
30255         mSystem = LengthUnit.metricSystem;
30256     } else if (measurementsystem === "imperial" || (typeof(measurementsystem) === 'undefined' 
30257             && typeof(LengthUnit.imperialSystem[this.unit]) !== 'undefined')) {
30258         mSystem = LengthUnit.imperialSystem;
30259     } else if (measurementsystem === "uscustomary" || (typeof(measurementsystem) === 'undefined' 
30260             && typeof(LengthUnit.uscustomarySystem[this.unit]) !== 'undefined')) {
30261         mSystem = LengthUnit.uscustomarySystem;
30262     } else {
30263         return new LengthUnit({
30264 			unit: this.unit,
30265 			amount: this.amount
30266 		});
30267     }    
30268     
30269     var length = this.amount;
30270     var munit = this.unit;
30271     var fromRow = LengthUnit.ratios[this.unit];
30272     
30273     length = 18446744073709551999;
30274     for (var m in mSystem) {
30275     	var tmp = this.amount * fromRow[mSystem[m]];
30276         if (tmp >= 1 && tmp < length) {
30277 	        length = tmp;
30278 	        munit = m;
30279         }
30280     }
30281     
30282     return new LengthUnit({
30283 		unit: munit,
30284 		amount: length
30285     });
30286 };
30287 
30288 LengthUnit.aliases = {
30289 	"miles": "mile",
30290 	"mile":"mile",
30291 	"nauticalmiles": "nauticalmile",
30292 	"nautical mile": "nauticalmile",
30293 	"nautical miles": "nauticalmile",
30294 	"nauticalmile":"nauticalmile",
30295 	"yards": "yard",
30296 	"yard": "yard",
30297 	"feet": "foot",
30298 	"foot": "foot",
30299 	"inches": "inch",
30300 	"inch": "inch",
30301 	"meters": "meter",
30302 	"metre": "meter",
30303 	"metres": "meter",
30304 	"m": "meter",
30305 	"meter": "meter",        
30306 	"micrometers": "micrometer",
30307 	"micrometres": "micrometer",
30308 	"micrometre": "micrometer",
30309 	"µm": "micrometer",
30310 	"micrometer": "micrometer",
30311 	"millimeters": "millimeter",
30312 	"millimetres": "millimeter",
30313 	"millimetre": "millimeter",
30314 	"mm": "millimeter",
30315 	"millimeter": "millimeter",
30316 	"centimeters": "centimeter",
30317 	"centimetres": "centimeter",
30318 	"centimetre": "centimeter",
30319 	"cm": "centimeter",
30320 	"centimeter": "centimeter",
30321 	"decimeters": "decimeter",
30322 	"decimetres": "decimeter",
30323 	"decimetre": "decimeter",
30324 	"dm": "decimeter",
30325 	"decimeter": "decimeter",
30326 	"decameters": "decameter",
30327 	"decametres": "decameter",
30328 	"decametre": "decameter",
30329 	"dam": "decameter",
30330 	"decameter": "decameter",
30331 	"hectometers": "hectometer",
30332 	"hectometres": "hectometer",
30333 	"hectometre": "hectometer",
30334 	"hm": "hectometer",
30335 	"hectometer": "hectometer",
30336 	"kilometers": "kilometer",
30337 	"kilometres": "kilometer",
30338 	"kilometre": "kilometer",
30339 	"km": "kilometer",
30340 	"kilometer": "kilometer",
30341 	"megameters": "megameter",
30342 	"megametres": "megameter",
30343 	"megametre": "megameter",
30344 	"Mm": "megameter",
30345 	"megameter": "megameter",
30346 	"gigameters": "gigameter",
30347 	"gigametres": "gigameter",
30348 	"gigametre": "gigameter",
30349 	"Gm": "gigameter",
30350 	"gigameter": "gigameter"
30351 };
30352 
30353 /**
30354  * Convert a length to another measure.
30355  * @static
30356  * @param to {string} unit to convert to
30357  * @param from {string} unit to convert from
30358  * @param length {number} amount to be convert
30359  * @returns {number|undefined} the converted amount
30360  */
30361 LengthUnit.convert = function(to, from, length) {
30362     from = LengthUnit.aliases[from] || from;
30363     to = LengthUnit.aliases[to] || to;
30364 	var fromRow = LengthUnit.ratios[from];
30365 	var toRow = LengthUnit.ratios[to];
30366 	if (typeof(from) === 'undefined' || typeof(to) === 'undefined') {
30367 		return undefined;
30368 	}
30369 	return length * fromRow[toRow[0]];
30370 };
30371 
30372 /**
30373  * @private
30374  * @static
30375  */
30376 LengthUnit.getMeasures = function () {
30377 	var ret = [];
30378 	for (var m in LengthUnit.ratios) {
30379 		ret.push(m);
30380 	}
30381 	return ret;
30382 };
30383 
30384 //register with the factory method
30385 Measurement._constructors["length"] = LengthUnit;
30386 
30387 
30388 /*< MassUnit.js */
30389 /*
30390  * MassUnit.js - Unit conversions for Mass/mass
30391  * 
30392  * Copyright © 2014-2015, JEDLSoft
30393  *
30394  * Licensed under the Apache License, Version 2.0 (the "License");
30395  * you may not use this file except in compliance with the License.
30396  * You may obtain a copy of the License at
30397  *
30398  *     http://www.apache.org/licenses/LICENSE-2.0
30399  *
30400  * Unless required by applicable law or agreed to in writing, software
30401  * distributed under the License is distributed on an "AS IS" BASIS,
30402  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
30403  *
30404  * See the License for the specific language governing permissions and
30405  * limitations under the License.
30406  */
30407 
30408 /*
30409 !depends 
30410 Measurement.js
30411 */
30412 
30413 
30414 /**
30415  * @class
30416  * Create a new mass measurement instance.
30417  *
30418  * @constructor
30419  * @extends Measurement
30420  * @param options {{unit:string,amount:number|string|undefined}} Options controlling 
30421  * the construction of this instance
30422  */
30423 var MassUnit = function (options) {
30424 	this.unit = "gram";
30425 	this.amount = 0;
30426 	this.aliases = MassUnit.aliases; // share this table in all instances
30427 	
30428 	if (options) {
30429 		if (typeof(options.unit) !== 'undefined') {
30430 			this.originalUnit = options.unit;
30431 			this.unit = this.aliases[options.unit] || options.unit;
30432 		}
30433 		
30434 		if (typeof(options.amount) === 'object') {
30435 			if (options.amount.getMeasure() === "mass") {
30436 				this.amount = MassUnit.convert(this.unit, options.amount.getUnit(), options.amount.getAmount());
30437 			} else {
30438 				throw "Cannot convert units " + options.amount.unit + " to a mass";
30439 			}
30440 		} else if (typeof(options.amount) !== 'undefined') {
30441 			this.amount = parseFloat(options.amount);
30442 		}
30443 	}
30444 	
30445 	if (typeof(MassUnit.ratios[this.unit]) === 'undefined') {
30446 		throw "Unknown unit: " + options.unit;
30447 	}
30448 };
30449 
30450 MassUnit.prototype = new Measurement();
30451 MassUnit.prototype.parent = Measurement;
30452 MassUnit.prototype.constructor = MassUnit;
30453 
30454 MassUnit.ratios = {
30455 	/*             index  µg          mg         g          oz          lp           kg          st            sh ton       mt ton        ln ton      */           
30456 	"microgram":   [ 1,   1,          0.001,     1e-6,      3.5274e-8,  2.2046e-9,   1e-9,       1.5747e-10,   1.1023e-12,  1e-12,        9.8421e-13   ],  
30457 	"milligram":   [ 2,   1000,       1,         0.001,     3.5274e-5,  2.2046e-6,   1e-6,       1.5747e-7,    1.1023e-9,   1e-9,         9.8421e-10   ],  
30458 	"gram":        [ 3,   1e+6,       1000,      1,         0.035274,   0.00220462,  0.001,      0.000157473,  1.1023e-6,   1e-6,         9.8421e-7    ],
30459 	"ounce":       [ 4,   2.835e+7,   28349.5,   28.3495,   1,          0.0625,      0.0283495,  0.00446429,   3.125e-5,    2.835e-5,     2.7902e-5    ],
30460 	"pound":       [ 5,   4.536e+8,   453592,    453.592,   16,         1,           0.453592,   0.0714286,    0.0005,      0.000453592,  0.000446429  ],
30461     "kilogram":    [ 6,   1e+9,       1e+6,      1000,      35.274,     2.20462,     1,          0.157473,     0.00110231,  0.001,        0.000984207  ],
30462     "stone":       [ 7,   6.35e+9,    6.35e+6,   6350.29,   224,        14,          6.35029,    1,            0.007,       0.00635029,   0.00625      ],
30463     "short ton":   [ 8,   9.072e+11,  9.072e+8,  907185,    32000,      2000,        907.185,    142.857,      1,           0.907185,     0.892857     ],
30464     "metric ton":  [ 9,   1e+12,      1e+9,      1e+6,      35274,      2204.62,     1000,       157.473,      1.10231,     1,            0.984207     ],
30465     "long ton":    [ 10,  1.016e+12,  1.016e+9,  1.016e+6,  35840,      2240,        1016.05,    160,          1.12,        1.01605,      1            ]
30466 };
30467 
30468 MassUnit.metricSystem = {
30469     "microgram": 1,
30470     "milligram": 2,
30471     "gram": 3,
30472     "kilogram": 6,
30473     "metric ton": 9
30474 };
30475 MassUnit.imperialSystem = {
30476     "ounce": 4,
30477     "pound": 5,
30478     "stone": 7,
30479     "long ton": 10
30480 };
30481 MassUnit.uscustomarySystem = {
30482     "ounce": 4,
30483     "pound": 5,
30484     "short ton": 8
30485 };
30486 
30487 MassUnit.metricToUScustomary = {
30488     "microgram": "ounce",
30489     "milligram": "ounce",
30490     "gram": "ounce",
30491     "kilogram": "pound",
30492     "metric ton": "long ton"
30493 };
30494 MassUnit.metricToImperial = {
30495     "microgram": "ounce",
30496     "milligram": "ounce",
30497     "gram": "ounce",
30498     "kilogram": "pound",
30499     "metric ton": "short ton"
30500 };
30501 
30502 MassUnit.imperialToMetric = {
30503     "ounce": "gram",
30504     "pound": "kilogram",
30505     "stone": "kilogram",
30506     "short ton": "metric ton"
30507 };
30508 MassUnit.imperialToUScustomary = {
30509     "ounce": "ounce",
30510     "pound": "pound",
30511     "stone": "stone",
30512     "short ton": "long ton"
30513 };
30514 
30515 MassUnit.uScustomaryToImperial = {
30516     "ounce": "ounce",
30517     "pound": "pound",
30518     "stone": "stone",
30519     "long ton": "short ton"
30520 };
30521 MassUnit.uScustomarylToMetric = {
30522     "ounce": "gram",
30523     "pound": "kilogram",
30524     "stone": "kilogram",
30525     "long ton": "metric ton"
30526 };
30527 
30528 /**
30529  * Localize the measurement to the commonly used measurement in that locale. For example
30530  * If a user's locale is "en-US" and the measurement is given as "60 kmh", 
30531  * the formatted number should be automatically converted to the most appropriate 
30532  * measure in the other system, in this case, mph. The formatted result should
30533  * appear as "37.3 mph". 
30534  * 
30535  * @param {string} locale current locale string
30536  * @returns {Measurement} a new instance that is converted to locale
30537  */
30538 MassUnit.prototype.localize = function(locale) {
30539 	var to;
30540 	if (locale === "en-US") {
30541 		to = MassUnit.metricToUScustomary[this.unit] ||
30542 		    MassUnit.imperialToUScustomary[this.unit] || this.unit;
30543 	} else if (locale === "en-GB") {
30544 		to = MassUnit.metricToImperial[this.unit] ||
30545 		    MassUnit.uScustomaryToImperial[this.unit] || this.unit;
30546 	} else {
30547 		to = MassUnit.uScustomarylToMetric[this.unit] ||
30548 		    MassUnit.imperialToUScustomary[this.unit] || this.unit;
30549 	}
30550 	return new MassUnit({
30551 	    unit: to,
30552 	    amount: this
30553 	});
30554 };
30555 
30556 /**
30557  * Return the type of this measurement. Examples are "mass",
30558  * "length", "speed", etc. Measurements can only be converted
30559  * to measurements of the same type.<p>
30560  * 
30561  * The type of the units is determined automatically from the 
30562  * units. For example, the unit "grams" is type "mass". Use the 
30563  * static call {@link Measurement.getAvailableUnits}
30564  * to find out what units this version of ilib supports.
30565  *  
30566  * @return {string} the name of the type of this measurement
30567  */
30568 MassUnit.prototype.getMeasure = function() {
30569 	return "mass";
30570 };
30571 
30572 /**
30573  * Return a new measurement instance that is converted to a new
30574  * measurement unit. Measurements can only be converted
30575  * to measurements of the same type.<p>
30576  *  
30577  * @param {string} to The name of the units to convert to
30578  * @return {Measurement|undefined} the converted measurement
30579  * or undefined if the requested units are for a different
30580  * measurement type 
30581  */
30582 MassUnit.prototype.convert = function(to) {
30583 	if (!to || typeof(MassUnit.ratios[this.normalizeUnits(to)]) === 'undefined') {
30584 		return undefined;
30585 	}
30586 	return new MassUnit({
30587 		unit: to,
30588 		amount: this
30589 	});
30590 };
30591 
30592 MassUnit.aliases = {
30593     "µg":"microgram",
30594     "microgram":"microgram",
30595     "mcg":"microgram",  
30596     "milligram":"milligram",
30597     "mg":"milligram",
30598     "milligrams":"milligram",
30599     "Milligram":"milligram",
30600     "Milligrams":"milligram",
30601     "MilliGram":"milligram",
30602     "MilliGrams":"milligram",
30603     "g":"gram",
30604     "gram":"gram",
30605     "grams":"gram",
30606     "Gram":"gram",
30607     "Grams":"gram",
30608     "ounce":"ounce",
30609     "oz":"ounce",
30610     "Ounce":"ounce",
30611     "℥":"ounce",
30612     "pound":"pound",
30613     "poundm":"pound",
30614     "℔":"pound",
30615     "lb":"pound",
30616     "pounds":"pound",
30617     "Pound":"pound",
30618     "Pounds":"pound",
30619     "kilogram":"kilogram",
30620     "kg":"kilogram",
30621     "kilograms":"kilogram",
30622     "kilo grams":"kilogram",
30623     "kilo gram":"kilogram",
30624     "Kilogram":"kilogram",    
30625     "Kilograms":"kilogram",
30626     "KiloGram":"kilogram",
30627     "KiloGrams":"kilogram",
30628     "Kilo gram":"kilogram",
30629     "Kilo grams":"kilogram",
30630     "Kilo Gram":"kilogram",
30631     "Kilo Grams":"kilogram",
30632     "stone":"stone",
30633     "st":"stone",
30634     "stones":"stone",
30635     "Stone":"stone",
30636     "short ton":"short ton",
30637     "Short ton":"short ton",
30638     "Short Ton":"short ton",
30639     "metric ton":"metric ton",
30640     "metricton":"metric ton",
30641     "t":"metric ton",
30642     "tonne":"metric ton",
30643     "Tonne":"metric ton",
30644     "Metric Ton":"metric ton",
30645     "MetricTon":"metric ton",    
30646     "long ton":"long ton",
30647     "longton":"long ton",
30648     "Longton":"long ton",
30649     "Long ton":"long ton",
30650     "Long Ton":"long ton",
30651     "ton":"long ton",
30652     "Ton":"long ton"
30653 };
30654 
30655 /**
30656  * Convert a mass to another measure.
30657  * @static
30658  * @param to {string} unit to convert to
30659  * @param from {string} unit to convert from
30660  * @param mass {number} amount to be convert
30661  * @returns {number|undefined} the converted amount
30662  */
30663 MassUnit.convert = function(to, from, mass) {
30664     from = MassUnit.aliases[from] || from;
30665     to = MassUnit.aliases[to] || to;
30666     var fromRow = MassUnit.ratios[from];
30667     var toRow = MassUnit.ratios[to];
30668     if (typeof(from) === 'undefined' || typeof(to) === 'undefined') {
30669         return undefined;
30670     }	
30671     return mass * fromRow[toRow[0]];    
30672 };
30673 
30674 /**
30675  * Scale the measurement unit to an acceptable level. The scaling
30676  * happens so that the integer part of the amount is as small as
30677  * possible without being below zero. This will result in the 
30678  * largest units that can represent this measurement without
30679  * fractions. Measurements can only be scaled to other measurements 
30680  * of the same type.
30681  * 
30682  * @param {string=} measurementsystem system to use (uscustomary|imperial|metric),
30683  * or undefined if the system can be inferred from the current measure
30684  * @return {Measurement} a new instance that is scaled to the 
30685  * right level
30686  */
30687 MassUnit.prototype.scale = function(measurementsystem) {
30688     var mSystem;    
30689     if (measurementsystem === "metric" || (typeof(measurementsystem) === 'undefined' 
30690             && typeof(MassUnit.metricSystem[this.unit]) !== 'undefined')) {
30691         mSystem = MassUnit.metricSystem;
30692     } else if (measurementsystem === "imperial" || (typeof(measurementsystem) === 'undefined' 
30693             && typeof(MassUnit.imperialSystem[this.unit]) !== 'undefined')) {
30694         mSystem = MassUnit.imperialSystem;
30695     } else if (measurementsystem === "uscustomary" || (typeof(measurementsystem) === 'undefined' 
30696             && typeof(MassUnit.uscustomarySystem[this.unit]) !== 'undefined')) {
30697         mSystem = MassUnit.uscustomarySystem;
30698     } else {
30699         return new MassUnit({
30700 			unit: this.unit,
30701 			amount: this.amount
30702 		});
30703     }    
30704     
30705     var mass = this.amount;
30706     var munit = this.amount;
30707     var fromRow = MassUnit.ratios[this.unit];
30708     
30709     mass = 18446744073709551999;
30710     
30711     for (var m in mSystem) {
30712         var tmp = this.amount * fromRow[mSystem[m]];
30713         if (tmp >= 1 && tmp < mass) {
30714         	mass = tmp;
30715             munit = m;
30716         }
30717     }
30718     
30719     return new MassUnit({
30720 		unit: munit,
30721 		amount: mass
30722     });
30723 };
30724 
30725 /**
30726  * @private
30727  * @static
30728  */
30729 MassUnit.getMeasures = function () {
30730 	var ret = [];
30731 	for (var m in MassUnit.ratios) {
30732 		ret.push(m);
30733 	}
30734 	return ret;
30735 };
30736 
30737 //register with the factory method
30738 Measurement._constructors["mass"] = MassUnit;
30739 
30740 
30741 /*< TemperatureUnit.js */
30742 /*
30743  * temperature.js - Unit conversions for Temperature/temperature
30744  * 
30745  * Copyright © 2014-2015, JEDLSoft
30746  *
30747  * Licensed under the Apache License, Version 2.0 (the "License");
30748  * you may not use this file except in compliance with the License.
30749  * You may obtain a copy of the License at
30750  *
30751  *     http://www.apache.org/licenses/LICENSE-2.0
30752  *
30753  * Unless required by applicable law or agreed to in writing, software
30754  * distributed under the License is distributed on an "AS IS" BASIS,
30755  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
30756  *
30757  * See the License for the specific language governing permissions and
30758  * limitations under the License.
30759  */
30760 
30761 /*
30762 !depends 
30763 Measurement.js
30764 */
30765 
30766 
30767 /**
30768  * @class
30769  * Create a new Temperature measurement instance.
30770  *  
30771  * @constructor
30772  * @extends Measurement
30773  * @param options {{unit:string,amount:number|string|undefined}} Options controlling 
30774  * the construction of this instance
30775  */
30776 var TemperatureUnit = function (options) {
30777 	this.unit = "celsius";
30778 	this.amount = 0;
30779 	this.aliases = TemperatureUnit.aliases; // share this table in all instances
30780 
30781 	if (options) {
30782 		if (typeof(options.unit) !== 'undefined') {
30783 			this.originalUnit = options.unit;
30784 			this.unit = this.aliases[options.unit] || options.unit;
30785 		}
30786 
30787 		if (typeof(options.amount) === 'object') {
30788 			if (options.amount.getMeasure() === "temperature") {
30789 				this.amount = TemperatureUnit.convert(this.unit, options.amount.getUnit(), options.amount.getAmount());
30790 			} else {
30791 				throw "Cannot convert unit " + options.amount.unit + " to a temperature";
30792 			}
30793 		} else if (typeof(options.amount) !== 'undefined') {
30794 			this.amount = parseFloat(options.amount);
30795 		}
30796 	}
30797 };
30798 
30799 TemperatureUnit.prototype = new Measurement();
30800 TemperatureUnit.prototype.parent = Measurement;
30801 TemperatureUnit.prototype.constructor = TemperatureUnit;
30802 
30803 /**
30804  * Return the type of this measurement. Examples are "mass",
30805  * "length", "speed", etc. Measurements can only be converted
30806  * to measurements of the same type.<p>
30807  * 
30808  * The type of the units is determined automatically from the 
30809  * units. For example, the unit "grams" is type "mass". Use the 
30810  * static call {@link Measurement.getAvailableUnits}
30811  * to find out what units this version of ilib supports.
30812  *  
30813  * @return {string} the name of the type of this measurement
30814  */
30815 TemperatureUnit.prototype.getMeasure = function() {
30816 	return "temperature";
30817 };
30818 
30819 TemperatureUnit.aliases = {
30820     "Celsius": "celsius",
30821     "celsius": "celsius",
30822     "C": "celsius",
30823     "centegrade": "celsius",
30824     "Centegrade": "celsius",
30825     "centigrade": "celsius",
30826     "Centigrade": "celsius",
30827     "fahrenheit": "fahrenheit",
30828     "Fahrenheit": "fahrenheit",
30829     "F": "fahrenheit",
30830     "kelvin": "kelvin",
30831     "K": "kelvin",
30832     "Kelvin": "kelvin",
30833     "°F": "fahrenheit",
30834     "℉": "fahrenheit",
30835     "℃": "celsius",
30836     "°C": "celsius"
30837 };
30838 
30839 /**
30840  * Return a new measurement instance that is converted to a new
30841  * measurement unit. Measurements can only be converted
30842  * to measurements of the same type.<p>
30843  *  
30844  * @param {string} to The name of the units to convert to
30845  * @return {Measurement|undefined} the converted measurement
30846  * or undefined if the requested units are for a different
30847  * measurement type 
30848  */
30849 TemperatureUnit.prototype.convert = function(to) {
30850 	if (!to || typeof(TemperatureUnit.ratios[this.normalizeUnits(to)]) === 'undefined') {
30851 		return undefined;
30852 	}
30853 	return new TemperatureUnit({
30854 		unit: to,
30855 		amount: this
30856 	});
30857 };
30858 
30859 /**
30860  * Convert a temperature to another measure.
30861  * @static
30862  * @param to {string} unit to convert to
30863  * @param from {string} unit to convert from
30864  * @param temperature {number} amount to be convert
30865  * @returns {number|undefined} the converted amount
30866  */
30867 TemperatureUnit.convert = function(to, from, temperature) {
30868 	var result = 0;
30869 	from = TemperatureUnit.aliases[from] || from;
30870 	to = TemperatureUnit.aliases[to] || to;
30871 	if (from === to)
30872 		return temperature;
30873 
30874 	else if (from === "celsius") {
30875 		if (to === "fahrenheit") {
30876 			result = ((temperature * 9 / 5) + 32);
30877 		} else if (to === "kelvin") {
30878 			result = (temperature + 273.15);
30879 		}
30880 
30881 	} else if (from === "fahrenheit") {
30882 		if (to === "celsius") {
30883 			result = ((5 / 9 * (temperature - 32)));
30884 		} else if (to === "kelvin") {
30885 			result = ((temperature + 459.67) * 5 / 9);
30886 		}
30887 	} else if (from === "kelvin") {
30888 		if (to === "celsius") {
30889 			result = (temperature - 273.15);
30890 		} else if (to === "fahrenheit") {
30891 			result = ((temperature * 9 / 5) - 459.67);
30892 		}
30893 	}
30894 
30895 	return result;
30896 };
30897 
30898 /**
30899  * Scale the measurement unit to an acceptable level. The scaling
30900  * happens so that the integer part of the amount is as small as
30901  * possible without being below zero. This will result in the 
30902  * largest units that can represent this measurement without
30903  * fractions. Measurements can only be scaled to other measurements 
30904  * of the same type.
30905  * 
30906  * @param {string=} measurementsystem system to use (uscustomary|imperial|metric),
30907  * or undefined if the system can be inferred from the current measure
30908  * @return {Measurement} a new instance that is scaled to the 
30909  * right level
30910  */
30911 TemperatureUnit.prototype.scale = function(measurementsystem) {
30912     return new TemperatureUnit({
30913         unit: this.unit,
30914         amount: this.amount
30915     }); 
30916 };
30917 
30918 /**
30919  * @private
30920  * @static
30921  */
30922 TemperatureUnit.getMeasures = function () {
30923 	return ["celsius", "kelvin", "fahrenheit"];
30924 };
30925 TemperatureUnit.metricToUScustomary = {
30926 	"celsius": "fahrenheit"
30927 };
30928 TemperatureUnit.usCustomaryToMetric = {
30929 	"fahrenheit": "celsius"
30930 };
30931 
30932 /**
30933  * Localize the measurement to the commonly used measurement in that locale. For example
30934  * If a user's locale is "en-US" and the measurement is given as "60 kmh", 
30935  * the formatted number should be automatically converted to the most appropriate 
30936  * measure in the other system, in this case, mph. The formatted result should
30937  * appear as "37.3 mph". 
30938  * 
30939  * @param {string} locale current locale string
30940  * @returns {Measurement} a new instance that is converted to locale
30941  */
30942 TemperatureUnit.prototype.localize = function(locale) {
30943     var to;
30944     if (locale === "en-US" ) {
30945         to = TemperatureUnit.metricToUScustomary[this.unit] || this.unit;
30946     } else {
30947         to = TemperatureUnit.usCustomaryToMetric[this.unit] || this.unit;
30948     }
30949     return new TemperatureUnit({
30950         unit: to,
30951         amount: this
30952     });
30953 };
30954 //register with the factory method
30955 Measurement._constructors["temperature"] = TemperatureUnit;
30956 
30957 
30958 /*< TimeUnit.js */
30959 /*
30960  * Time.js - Unit conversions for Times/times
30961  * 
30962  * Copyright © 2014-2015, JEDLSoft
30963  *
30964  * Licensed under the Apache License, Version 2.0 (the "License");
30965  * you may not use this file except in compliance with the License.
30966  * You may obtain a copy of the License at
30967  *
30968  *     http://www.apache.org/licenses/LICENSE-2.0
30969  *
30970  * Unless required by applicable law or agreed to in writing, software
30971  * distributed under the License is distributed on an "AS IS" BASIS,
30972  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
30973  *
30974  * See the License for the specific language governing permissions and
30975  * limitations under the License.
30976  */
30977 
30978 /*
30979 !depends 
30980 Measurement.js
30981 */
30982 
30983 
30984 /**
30985  * @class
30986  * Create a new time measurement instance.
30987  * 
30988  * @constructor
30989  * @extends Measurement
30990  * @param options {{unit:string,amount:number|string|undefined}} Options controlling 
30991  * the construction of this instance
30992  */
30993 var TimeUnit = function (options) {
30994 	this.unit = "second";
30995 	this.amount = 0;
30996 	this.aliases = TimeUnit.aliases; // share this table in all instances
30997 	
30998 	if (options) {
30999 		if (typeof(options.unit) !== 'undefined') {
31000 			this.originalUnit = options.unit;
31001 			this.unit = this.aliases[options.unit] || options.unit;
31002 		}
31003 		
31004 		if (typeof(options.amount) === 'object') {
31005 			if (options.amount.getMeasure() === "time") {
31006 				this.amount = TimeUnit.convert(this.unit, options.amount.getUnit(), options.amount.getAmount());
31007 			} else {
31008 				throw "Cannot convert units " + options.amount.unit + " to a time";
31009 			}
31010 		} else if (typeof(options.amount) !== 'undefined') {
31011 			this.amount = parseFloat(options.amount);
31012 		}
31013 	}
31014 	
31015 	if (typeof(TimeUnit.ratios[this.unit]) === 'undefined') {
31016 		throw "Unknown unit: " + options.unit;
31017 	}
31018 };
31019 
31020 TimeUnit.prototype = new Measurement();
31021 TimeUnit.prototype.parent = Measurement;
31022 TimeUnit.prototype.constructor = TimeUnit;
31023 
31024 TimeUnit.ratios = {
31025 	/*              index  nsec        msec        mlsec       sec        min          hour          day           week         month        year         decade        century    */           
31026 	"nanosecond":   [ 1,   1,          0.001,      1e-6,       1e-9,      1.6667e-11,  2.7778e-13,   1.1574e-14,   1.6534e-15,  3.8027e-16,  3.1689e-17,  3.1689e-18,   3.1689e-19  ],  
31027 	"microsecond":  [ 2,   1000,       1,          0.001,      1e-6,      1.6667e-8,   2.7778e-10,   1.1574e-11,   1.6534e-12,  3.8027e-13,  3.1689e-14,  3.1689e-15,   3.1689e-16  ],  
31028 	"millisecond":  [ 3,   1e+6,       1000,       1,          0.001,     1.6667e-5,   2.7778e-7,    1.1574e-8,    1.6534e-9,   3.8027e-10,  3.1689e-11,  3.1689e-12,   3.1689e-13  ],
31029 	"second":       [ 4,   1e+9,       1e+6,       1000,       1,         0.0166667,   0.000277778,  1.1574e-5,    1.6534e-6,   3.8027e-7,   3.1689e-8,   3.1689e-9,    3.1689e-10  ],
31030 	"minute":       [ 5,   6e+10,      6e+7,       60000,      60,        1,           0.0166667,    0.000694444,  9.9206e-5,   2.2816e-5,   1.9013e-6,   1.9013e-7,    1.9013e-8   ],
31031     "hour":         [ 6,   3.6e+12,    3.6e+9,     3.6e+6,     3600,      60,          1,            0.0416667,    0.00595238,  0.00136895,  0.00011408,  1.1408e-5,    1.1408e-6   ],
31032     "day":          [ 7,   8.64e+13,   8.64e+10,   8.64e+7,    86400,     1440,        24,           1,            0.142857,    0.0328549,   0.00273791,  0.000273791,  2.7379e-5   ],
31033     "week":         [ 8,   6.048e+14,  6.048e+11,  6.048e+8,   604800,    10080,       168,          7,            1,           0.229984,    0.0191654,   0.00191654,   0.000191654 ],
31034     "month":        [ 9,   2.63e+15,   2.63e+12,   2.63e+9,    2.63e+6,   43829.1,     730.484,      30.4368,      4.34812,     1,           0.0833333,   0.00833333,   0.000833333 ],
31035     "year":         [ 10,  3.156e+16,  3.156e+13,  3.156e+10,  3.156e+7,  525949,      8765.81,      365.242,      52.1775,     12,          1,           0.1,          0.01        ],
31036     "decade":       [ 11,  3.156e+17,  3.156e+14,  3.156e+11,  3.156e+8,  5.259e+6,    87658.1,      3652.42,      521.775,     120,         10,          1,            0.1         ],
31037     "century":      [ 12,  3.156e+18,  3.156e+18,  3.156e+12,  3.156e+9,  5.259e+7,    876581,       36524.2,      5217.75,     1200,        100,         10,           1           ]
31038 };
31039 
31040 /**
31041  * Return the type of this measurement. Examples are "mass",
31042  * "length", "speed", etc. Measurements can only be converted
31043  * to measurements of the same type.<p>
31044  * 
31045  * The type of the units is determined automatically from the 
31046  * units. For example, the unit "grams" is type "mass". Use the 
31047  * static call {@link Measurement.getAvailableUnits}
31048  * to find out what units this version of ilib supports.
31049  *  
31050  * @return {string} the name of the type of this measurement
31051  */
31052 TimeUnit.prototype.getMeasure = function() {
31053 	return "time";
31054 };
31055 
31056 /**
31057  * Return a new measurement instance that is converted to a new
31058  * measurement unit. Measurements can only be converted
31059  * to measurements of the same type.<p>
31060  *  
31061  * @param {string} to The name of the units to convert to
31062  * @return {Measurement|undefined} the converted measurement
31063  * or undefined if the requested units are for a different
31064  * measurement type 
31065  */
31066 TimeUnit.prototype.convert = function(to) {
31067 	if (!to || typeof(TimeUnit.ratios[this.normalizeUnits(to)]) === 'undefined') {
31068 		return undefined;
31069 	}
31070 	return new TimeUnit({
31071 		unit: to,
31072 		amount: this
31073 	});
31074 };
31075 
31076 TimeUnit.aliases = {
31077     "ns": "nanosecond",
31078     "NS": "nanosecond",
31079     "nS": "nanosecond",
31080     "Ns": "nanosecond",
31081     "Nanosecond": "nanosecond",
31082     "Nanoseconds": "nanosecond",
31083     "nanosecond": "nanosecond",
31084     "nanoseconds": "nanosecond",
31085     "NanoSecond": "nanosecond",
31086     "NanoSeconds": "nanosecond",
31087     "μs": "microsecond",
31088     "μS": "microsecond",
31089     "microsecond": "microsecond",
31090     "microseconds": "microsecond",
31091     "Microsecond": "microsecond",
31092     "Microseconds": "microsecond",
31093     "MicroSecond": "microsecond",
31094     "MicroSeconds": "microsecond",
31095     "ms": "millisecond",
31096     "MS": "millisecond",
31097     "mS": "millisecond",
31098     "Ms": "millisecond",
31099     "millisecond": "millisecond",
31100     "milliseconds": "millisecond",
31101     "Millisecond": "millisecond",
31102     "Milliseconds": "millisecond",
31103     "MilliSecond": "millisecond",
31104     "MilliSeconds": "millisecond",
31105     "s": "second",
31106     "S": "second",
31107     "sec": "second",
31108     "second": "second",
31109     "seconds": "second",
31110     "Second": "second",
31111     "Seconds": "second",
31112     "min": "minute",
31113     "Min": "minute",
31114     "minute": "minute",
31115     "minutes": "minute",
31116     "Minute": "minute",
31117     "Minutes": "minute",
31118     "h": "hour",
31119     "H": "hour",
31120     "hr": "hour",
31121     "Hr": "hour",
31122     "hR": "hour",
31123     "HR": "hour",
31124     "hour": "hour",
31125     "hours": "hour",
31126     "Hour": "hour",
31127     "Hours": "hour",
31128     "Hrs": "hour",
31129     "hrs": "hour",
31130     "day": "day",
31131     "days": "day",
31132     "Day": "day",
31133     "Days": "day",
31134     "week": "week",
31135     "weeks": "week",
31136     "Week": "week",
31137     "Weeks": "week",
31138     "month": "month",
31139     "Month": "month",
31140     "months": "month",
31141     "Months": "month",
31142     "year": "year",
31143     "years": "year",
31144     "Year": "year",
31145     "Years": "year",
31146     "yr": "year",
31147     "Yr": "year",
31148     "yrs": "year",
31149     "Yrs": "year",
31150     "decade": "decade",
31151     "decades": "decade",
31152     "Decade": "decade",
31153     "Decades": "decade",
31154     "century": "century",
31155     "centuries": "century",
31156     "Century": "century",
31157     "Centuries": "century"
31158 };
31159 
31160 /**
31161  * Convert a time to another measure.
31162  * @static
31163  * @param to {string} unit to convert to
31164  * @param from {string} unit to convert from
31165  * @param time {number} amount to be convert
31166  * @returns {number|undefined} the converted amount
31167  */
31168 TimeUnit.convert = function(to, from, time) {
31169     from = TimeUnit.aliases[from] || from;
31170     to = TimeUnit.aliases[to] || to;
31171     var fromRow = TimeUnit.ratios[from];
31172     var toRow = TimeUnit.ratios[to];
31173     if (typeof(from) === 'undefined' || typeof(to) === 'undefined') {
31174         return undefined;
31175     }	
31176     return time * fromRow[toRow[0]];
31177 };
31178 
31179 /**
31180  * Localize the measurement to the commonly used measurement in that locale. For example
31181  * If a user's locale is "en-US" and the measurement is given as "60 kmh", 
31182  * the formatted number should be automatically converted to the most appropriate 
31183  * measure in the other system, in this case, mph. The formatted result should
31184  * appear as "37.3 mph". 
31185  * 
31186  * @param {string} locale current locale string
31187  * @returns {Measurement} a new instance that is converted to locale
31188  */
31189 TimeUnit.prototype.localize = function(locale) {
31190     return new TimeUnit({
31191         unit: this.unit,
31192         amount: this.amount
31193     });
31194 };
31195 
31196 /**
31197  * Scale the measurement unit to an acceptable level. The scaling
31198  * happens so that the integer part of the amount is as small as
31199  * possible without being below zero. This will result in the 
31200  * largest units that can represent this measurement without
31201  * fractions. Measurements can only be scaled to other measurements 
31202  * of the same type.
31203  * 
31204  * @param {string=} measurementsystem system to use (uscustomary|imperial|metric),
31205  * or undefined if the system can be inferred from the current measure
31206  * @return {Measurement} a new instance that is scaled to the 
31207  * right level
31208  */
31209 TimeUnit.prototype.scale = function(measurementsystem) {
31210 
31211     var fromRow = TimeUnit.ratios[this.unit];
31212     var time = this.amount;
31213     var munit = this.unit;
31214     var i;
31215 
31216     time = 18446744073709551999;
31217     for (var m in TimeUnit.ratios) {
31218     	i = TimeUnit.ratios[m][0];
31219     	var tmp = this.amount * fromRow[i];
31220     	if (tmp >= 1 && tmp < time) {
31221 	        time = tmp;
31222 	        munit = m;
31223     	}
31224     }
31225 
31226     return new TimeUnit({
31227         unit: munit,
31228         amount: time
31229     });
31230 };
31231 /**
31232  * @private
31233  * @static
31234  */
31235 TimeUnit.getMeasures = function () {
31236 	var ret = [];
31237 	for (var m in TimeUnit.ratios) {
31238 		ret.push(m);
31239 	}
31240 	return ret;
31241 };
31242 
31243 //register with the factory method
31244 Measurement._constructors["time"] = TimeUnit;
31245 
31246 
31247 /*< VelocityUnit.js */
31248 /*
31249  * VelocityUnit.js - Unit conversions for VelocityUnits/speeds
31250  * 
31251  * Copyright © 2014-2015, JEDLSoft
31252  *
31253  * Licensed under the Apache License, Version 2.0 (the "License");
31254  * you may not use this file except in compliance with the License.
31255  * You may obtain a copy of the License at
31256  *
31257  *     http://www.apache.org/licenses/LICENSE-2.0
31258  *
31259  * Unless required by applicable law or agreed to in writing, software
31260  * distributed under the License is distributed on an "AS IS" BASIS,
31261  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
31262  *
31263  * See the License for the specific language governing permissions and
31264  * limitations under the License.
31265  */
31266 
31267 /*
31268 !depends 
31269 Measurement.js
31270 */
31271 
31272 
31273 /**
31274  * @class
31275  * Create a new speed measurement instance.
31276  * 
31277  * @constructor
31278  * @extends Measurement
31279  * @param options {{unit:string,amount:number|string|undefined}} Options controlling 
31280  * the construction of this instance
31281  */
31282 var VelocityUnit = function (options) {
31283 	this.unit = "meters/second";
31284 	this.amount = 0;
31285 	this.aliases = VelocityUnit.aliases; // share this table in all instances
31286 	
31287 	if (options) {
31288 		if (typeof(options.unit) !== 'undefined') {
31289 			this.originalUnit = options.unit;
31290 			this.unit = this.aliases[options.unit] || options.unit;
31291 		}
31292 		
31293 		if (typeof(options.amount) === 'object') {
31294 			if (options.amount.getMeasure() === "speed") {
31295 				this.amount = VelocityUnit.convert(this.unit, options.amount.getUnit(), options.amount.getAmount());
31296 			} else {
31297 				throw "Cannot convert units " + options.amount.unit + " to a speed";
31298 			}
31299 		} else if (typeof(options.amount) !== 'undefined') {
31300 			this.amount = parseFloat(options.amount);
31301 		}
31302 	}
31303 	
31304 	if (typeof(VelocityUnit.ratios[this.unit]) === 'undefined') {
31305 		throw "Unknown unit: " + options.unit;
31306 	}
31307 };
31308 
31309 VelocityUnit.prototype = new Measurement();
31310 VelocityUnit.prototype.parent = Measurement;
31311 VelocityUnit.prototype.constructor = VelocityUnit;
31312 
31313 VelocityUnit.ratios = {
31314 	/*                 index, k/h         f/s         miles/h      knot         m/s        km/s         miles/s */
31315     "kilometer/hour":   [ 1,  1,          0.911344,   0.621371,    0.539957,    0.277778,  2.77778e-4,  1.72603109e-4 ],
31316 	"feet/second":      [ 2,  1.09728,    1,          0.681818,    0.592484,    0.3048,    3.048e-4,    1.89393939e-4 ],  
31317     "miles/hour":       [ 3,  1.60934,    1.46667,    1,           0.868976,    0.44704,   4.4704e-4,   2.77777778e-4 ],
31318     "knot":             [ 4,  1.852,      1.68781,    1.15078,     1,           0.514444,  5.14444e-4,  3.19660958e-4 ],
31319   	"meters/second":    [ 5,  3.6,        3.28084,    2.236936,    1.94384,     1,         0.001,       6.21371192e-4 ],	
31320     "kilometer/second": [ 6,  3600,       3280.8399,  2236.93629,  1943.84449,  1000,      1,           0.621371192   ],
31321     "miles/second":     [ 7,  5793.6384,  5280,       3600,        3128.31447,  1609.344,  1.609344,    1             ]
31322 };
31323 
31324 VelocityUnit.metricSystem = {
31325     "kilometer/hour": 1,
31326     "meters/second": 5,
31327     "kilometer/second": 6
31328 };
31329 VelocityUnit.imperialSystem = {
31330     "feet/second": 2,
31331     "miles/hour": 3,
31332     "knot": 4,
31333     "miles/second": 7
31334 };
31335 VelocityUnit.uscustomarySystem = {
31336     "feet/second": 2,
31337     "miles/hour": 3,
31338     "knot": 4,
31339     "miles/second": 7
31340 };
31341 
31342 VelocityUnit.metricToUScustomary = {
31343     "kilometer/hour": "miles/hour",
31344     "meters/second": "feet/second",
31345     "kilometer/second": "miles/second"
31346 };
31347 VelocityUnit.UScustomaryTometric = {
31348     "miles/hour": "kilometer/hour",
31349     "feet/second": "meters/second",
31350     "miles/second": "kilometer/second",
31351     "knot": "kilometer/hour"
31352 };
31353 
31354 /**
31355  * Return the type of this measurement. Examples are "mass",
31356  * "length", "speed", etc. Measurements can only be converted
31357  * to measurements of the same type.<p>
31358  * 
31359  * The type of the units is determined automatically from the 
31360  * units. For example, the unit "grams" is type "mass". Use the 
31361  * static call {@link Measurement.getAvailableUnits}
31362  * to find out what units this version of ilib supports.
31363  *  
31364  * @return {string} the name of the type of this measurement
31365  */
31366 VelocityUnit.prototype.getMeasure = function() {
31367 	return "speed";
31368 };
31369 
31370 /**
31371  * Return a new measurement instance that is converted to a new
31372  * measurement unit. Measurements can only be converted
31373  * to measurements of the same type.<p>
31374  *  
31375  * @param {string} to The name of the units to convert to
31376  * @return {Measurement|undefined} the converted measurement
31377  * or undefined if the requested units are for a different
31378  * measurement type 
31379  */
31380 VelocityUnit.prototype.convert = function(to) {
31381 	if (!to || typeof(VelocityUnit.ratios[this.normalizeUnits(to)]) === 'undefined') {
31382 		return undefined;
31383 	}
31384 	return new VelocityUnit({
31385 		unit: to,
31386 		amount: this
31387 	});
31388 };
31389 
31390 /**
31391  * Scale the measurement unit to an acceptable level. The scaling
31392  * happens so that the integer part of the amount is as small as
31393  * possible without being below zero. This will result in the 
31394  * largest units that can represent this measurement without
31395  * fractions. Measurements can only be scaled to other measurements 
31396  * of the same type.
31397  * 
31398  * @param {string=} measurementsystem system to use (uscustomary|imperial|metric),
31399  * or undefined if the system can be inferred from the current measure
31400  * @return {Measurement} a new instance that is scaled to the 
31401  * right level
31402  */
31403 VelocityUnit.prototype.scale = function(measurementsystem) {
31404 	var mSystem;
31405 	if (measurementsystem === "metric" ||
31406 	    (typeof (measurementsystem) === 'undefined' && typeof (VelocityUnit.metricSystem[this.unit]) !== 'undefined')) {
31407 		mSystem = VelocityUnit.metricSystem;
31408 	} else if (measurementsystem === "imperial" ||
31409 	    (typeof (measurementsystem) === 'undefined' && typeof (VelocityUnit.imperialSystem[this.unit]) !== 'undefined')) {
31410 		mSystem = VelocityUnit.imperialSystem;
31411 	} else if (measurementsystem === "uscustomary" ||
31412 	    (typeof (measurementsystem) === 'undefined' && typeof (VelocityUnit.uscustomarySystem[this.unit]) !== 'undefined')) {
31413 		mSystem = VelocityUnit.uscustomarySystem;
31414 	} else {
31415 		return new VelocityUnit({
31416 		    unit: this.unit,
31417 		    amount: this.amount
31418 		});
31419 	}
31420 
31421 	var speed = this.amount;
31422 	var munit = this.unit;
31423 	var fromRow = VelocityUnit.ratios[this.unit];
31424 
31425 	speed = 18446744073709551999;
31426 	
31427     for ( var m in mSystem) {
31428 		var tmp = this.amount * fromRow[mSystem[m]];
31429 		if (tmp >= 1 && tmp < speed) {
31430 			speed = tmp;
31431 			munit = m;
31432 		}
31433 	}
31434 
31435 	return new VelocityUnit({
31436 	    unit: munit,
31437 	    amount: speed
31438 	});
31439 };
31440 
31441 /**
31442  * Localize the measurement to the commonly used measurement in that locale. For example
31443  * If a user's locale is "en-US" and the measurement is given as "60 kmh", 
31444  * the formatted number should be automatically converted to the most appropriate 
31445  * measure in the other system, in this case, mph. The formatted result should
31446  * appear as "37.3 mph". 
31447  * 
31448  * @param {string} locale current locale string
31449  * @returns {Measurement} a new instance that is converted to locale
31450  */
31451 VelocityUnit.prototype.localize = function(locale) {
31452     var to;
31453     if (locale === "en-US" || locale === "en-GB") {
31454         to = VelocityUnit.metricToUScustomary[this.unit] || this.unit;
31455     } else {
31456         to = VelocityUnit.UScustomaryTometric[this.unit] || this.unit;
31457     }
31458     return new VelocityUnit({
31459 		unit: to,
31460 		amount: this
31461     });
31462 };
31463 
31464 VelocityUnit.aliases = {
31465     "foot/sec": "feet/second",
31466     "foot/s": "feet/second",
31467     "feet/s": "feet/second",
31468     "f/s": "feet/second",
31469     "feet/second": "feet/second",
31470     "feet/sec": "feet/second",
31471     "meter/sec": "meters/second",
31472     "meter/s": "meters/second",
31473     "meters/s": "meters/second",
31474     "metre/sec": "meters/second",
31475     "metre/s": "meters/second",
31476     "metres/s": "meters/second",
31477     "mt/sec": "meters/second",
31478     "m/sec": "meters/second",
31479     "mt/s": "meters/second",
31480     "m/s": "meters/second",
31481     "mps": "meters/second",
31482     "meters/second": "meters/second",
31483     "meters/sec": "meters/second",
31484     "kilometer/hour": "kilometer/hour",
31485     "km/hour": "kilometer/hour",
31486     "kilometers/hour": "kilometer/hour",
31487     "kmh": "kilometer/hour",
31488     "km/h": "kilometer/hour",
31489     "kilometer/h": "kilometer/hour",
31490     "kilometers/h": "kilometer/hour",
31491     "km/hr": "kilometer/hour",
31492     "kilometer/hr": "kilometer/hour",
31493     "kilometers/hr": "kilometer/hour",
31494     "kilometre/hour": "kilometer/hour",
31495     "mph": "miles/hour",
31496     "mile/hour": "miles/hour",
31497     "mile/hr": "miles/hour",
31498     "mile/h": "miles/hour",
31499     "miles/h": "miles/hour",
31500     "miles/hr": "miles/hour",
31501     "miles/hour": "miles/hour",
31502     "kn": "knot",
31503     "kt": "knot",
31504     "kts": "knot",
31505     "knots": "knot",
31506     "nm/h": "knot",
31507     "nm/hr": "knot",
31508     "nauticalmile/h": "knot",
31509     "nauticalmile/hr": "knot",
31510     "nauticalmile/hour": "knot",
31511     "nauticalmiles/hr": "knot",
31512     "nauticalmiles/hour": "knot",
31513     "knot": "knot",
31514     "kilometer/second": "kilometer/second",
31515     "kilometer/sec": "kilometer/second",
31516     "kilometre/sec": "kilometer/second",
31517     "Kilometre/sec": "kilometer/second",
31518     "kilometers/second": "kilometer/second",
31519     "kilometers/sec": "kilometer/second",
31520     "kilometres/sec": "kilometer/second",
31521     "Kilometres/sec": "kilometer/second",
31522     "km/sec": "kilometer/second",
31523     "Km/s": "kilometer/second",
31524     "km/s": "kilometer/second",
31525     "miles/second": "miles/second",
31526     "miles/sec": "miles/second",
31527     "miles/s": "miles/second",
31528     "mile/s": "miles/second",
31529     "mile/sec": "miles/second",
31530     "Mile/s": "miles/second"
31531 };
31532 
31533 /**
31534  * Convert a speed to another measure.
31535  * @static
31536  * @param to {string} unit to convert to
31537  * @param from {string} unit to convert from
31538  * @param speed {number} amount to be convert
31539  * @returns {number|undefined} the converted amount
31540  */
31541 VelocityUnit.convert = function(to, from, speed) {
31542     from = VelocityUnit.aliases[from] || from;
31543     to = VelocityUnit.aliases[to] || to;
31544 	var fromRow = VelocityUnit.ratios[from];
31545 	var toRow = VelocityUnit.ratios[to];
31546 	if (typeof(from) === 'undefined' || typeof(to) === 'undefined') {
31547 		return undefined;
31548 	}	
31549 	var result = speed * fromRow[toRow[0]];
31550     return result;
31551 };
31552 
31553 /**
31554  * @private
31555  * @static
31556  */
31557 VelocityUnit.getMeasures = function () {
31558 	var ret = [];
31559 	for (var m in VelocityUnit.ratios) {
31560 		ret.push(m);
31561 	}
31562 	return ret;
31563 };
31564 
31565 //register with the factory method
31566 Measurement._constructors["speed"] = VelocityUnit;
31567 Measurement._constructors["velocity"] = VelocityUnit;
31568 
31569 
31570 /*< VolumeUnit.js */
31571 /*
31572  * volume.js - Unit conversions for volume
31573  * 
31574  * Copyright © 2014-2015, JEDLSoft
31575  *
31576  * Licensed under the Apache License, Version 2.0 (the "License");
31577  * you may not use this file except in compliance with the License.
31578  * You may obtain a copy of the License at
31579  *
31580  *     http://www.apache.org/licenses/LICENSE-2.0
31581  *
31582  *
31583  * Unless required by applicable law or agreed to in writing, software
31584  * distributed under the License is distributed on an "AS IS" BASIS,
31585  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
31586  *
31587  * See the License for the specific language governing permissions and
31588  * limitations under the License.
31589  */
31590 
31591 /*
31592 !depends 
31593 Measurement.js
31594 */
31595 
31596 
31597 /**
31598  * @class
31599  * Create a new Volume measurement instance.
31600  * 
31601  * @constructor
31602  * @extends Measurement
31603  * @param options {{unit:string,amount:number|string|undefined}} Options controlling 
31604  * the construction of this instance
31605  */
31606 var VolumeUnit = function (options) {
31607 	this.unit = "cubic meter";
31608 	this.amount = 0;
31609 	this.aliases = VolumeUnit.aliases; // share this table in all instances
31610 	
31611 	if (options) {
31612 		if (typeof(options.unit) !== 'undefined') {
31613 			this.originalUnit = options.unit;
31614 			this.unit = this.aliases[options.unit] || options.unit;
31615 		}
31616 		
31617 		if (typeof(options.amount) === 'object') {
31618 			if (options.amount.getMeasure() === "volume") {
31619 				this.amount = VolumeUnit.convert(this.unit, options.amount.getUnit(), options.amount.getAmount());
31620 			} else {
31621 				throw "Cannot convert unit " + options.amount.unit + " to a volume";
31622 			}
31623 		} else if (typeof(options.amount) !== 'undefined') {
31624 			this.amount = parseFloat(options.amount);
31625 		}
31626 	}
31627 	
31628 	if (typeof(VolumeUnit.ratios[this.unit]) === 'undefined') {
31629 		throw "Unknown unit: " + options.unit;
31630 	}
31631 };
31632 
31633 VolumeUnit.prototype = new Measurement();
31634 VolumeUnit.prototype.parent = Measurement;
31635 VolumeUnit.prototype.constructor = VolumeUnit;
31636 
31637 VolumeUnit.ratios = {
31638     /*                 index, tsp,      tbsp,          cubic inch  us ounce, cup,        pint,       quart,      gallon,      cubic foot,  milliliter  liter,      cubic meter, imperial tsp,  imperial tbsp, imperial ounce,  imperial pint,  imperial quart, imperial gal, */
31639     "tsp" :            [1,    1,        0.333333,      0.300781,   0.166667, 0.0208333,  0.0104167,  0.00520833, 0.00130208,  0.000174063, 4.92892,    0.00492892, 4.9289e-6,   0.832674,      0.277558,      0.173474,        0.00867369,     0.00433684,     0.00108421          ],
31640     "tbsp":            [2,    3,        1,             0.902344,   0.5,      0.0625,     0.0312,     0.015625,   0.00390625,  0.00052219,  14.7868,    0.0147868,  1.4787e-5,   2.49802,       0.832674,      0.520421,        0.0260211,      0.0130105,      0.00325263          ],
31641     "cubic inch":      [3,    3.32468,  1.10823,       1,          0.554113, 0.0692641,  0.034632,   0.017316,   0.004329,    0.000578704, 16.3871,    0.0163871,  1.6387e-5,   2.76837,       0.92279,       0.576744,        0.0288372,      0.0144186,      0.00360465          ],
31642     "us ounce":        [4,    6,        2,             1.80469,    1,        0.125,      0.0625,     0.0078125,  0.0078125,   0.00104438,  29.5735,    0.0295735,  2.9574e-5,   4.99604,       1.04084,       1.04084,         0.0520421,      0.0260211,      0.00650526          ],
31643     "cup":             [5,    48,       16,            14.4375,    8,        1,          0.5,        0.25,       0.0625,      0.00835503,  236.588,    0.236588,   0.000236588, 39.9683,       13.3228,       8.32674,         0.416337,       0.208168,       0.0520421           ],
31644     "pint":            [6,    96,       32,            28.875,     16,       2,          1,          0.5,        0.125,       0.0167101,   473.176,    0.473176,   0.000473176, 79.9367,       26.6456,       16.6535,         0.832674,       0.416337,       0.104084            ],
31645     "quart":           [7,    192,      64,            57.75,      32,       4,          2,          1,          0.25,        0.0334201,   946.353,    0.946353,   0.000946353, 159.873,       53.2911,       33.307,          1.66535,        0.832674,       0.208168            ],
31646     "gallon":          [8,    768,      256,           231,        128,      16,         8,          4,          1,           0.133681,    3785.41,    3.78541,    0.00378541,  639.494,       213.165,       133.228,         6.66139,        3.3307,         0.832674            ],
31647     "cubic foot":      [9,    5745.04,  1915.01,       1728,       957.506,  119.688,    59.8442,    29.9221,    7.48052,     1,           28316.8,    28.3168,    0.0283168,   4783.74,       1594.58,       996.613,         49.8307,        24.9153,        6.22883             ],
31648     "milliliter":      [10,   0.202884, 0.067628,      0.0610237,  0.033814, 0.00422675, 0.00211338, 0.00105669, 0.000264172, 3.5315e-5,   1,          0.001,      1e-6,        0.168936,      0.0563121,     0.0351951,       0.00175975,     0.000879877,    0.000219969         ],
31649     "liter":           [11,   202.884,  67.628,        61.0237,    33.814,   4.22675,    2.11338,    1.05669,    0.264172,    0.0353147,   1000,       1,          0.001,       56.3121,       56.3121,       35.191,          1.75975,        0.879877,       0.219969            ],
31650     "cubic meter":     [12,   202884,   67628,         61023.7,    33814,    4226.75,    2113.38,    1056.69,    264.172,     35.3147,     1e+6,       1000,       1,           168936,        56312.1,       35195.1,         1759.75,        879.877,        219.969             ],
31651     "imperial tsp":    [13,   1.20095,  0.200158,      0.361223,   0.600475, 0.0250198,  0.0125099,  0.00625495, 0.00156374,  0.000209041, 5.91939,    0.00591939, 5.9194e-6,   1,             0.333333,      0.208333,        0.0104167,      0.00520833,     0.00130208          ],
31652     "imperial tbsp":   [14,   3.60285,  1.20095,       1.08367,    0.600475, 0.0750594,  0.0375297,  0.0187649,  0.00469121,  0.000627124, 17.7582,    0.0177582,  1.7758e-5,   3,             1,             0.625,           0.03125,        0.015625,       0.00390625          ],
31653     "imperial ounce":  [15,   5.76456,  1.92152,       1.73387,    0.96076,  0.120095,   0.0600475,  0.0300238,  0.00750594,  0.0010034,   28.4131,    0.0284131,  2.8413e-5,   4.8,           1.6,           1,               0.05,           0.025,          0.00625             ],
31654     "imperial pint":   [16,   115.291,  38.4304,       34.6774,    19.2152,  2.4019,     1.20095,    0.600475,   0.150119,    0.020068,    568.261,    0.568261,   0.000568261, 96,            32,            20,              1,              0.5,            0.125               ],
31655     "imperial quart":  [17,   230.582,  76.8608,       69.3549,    38.4304,  4.8038,     2.4019,     1.20095,    0.300238,    0.0401359,   1136.52,    1.13652,    0.00113652,  192,           64,            40,              2,              1,              0.25                ],
31656     "imperial gallon": [18,   922.33,   307.443,       277.42,     153.722,  19.2152,    9.6076,     4.8038,     1.20095,     0.160544,    4546.09,    4.54609,    0.00454609,  768,           256,           160,             8,              4,              1                   ]
31657 };
31658 
31659 /**
31660  * Return the type of this measurement. Examples are "mass",
31661  * "length", "speed", etc. Measurements can only be converted
31662  * to measurements of the same type.<p>
31663  * 
31664  * The type of the units is determined automatically from the 
31665  * units. For example, the unit "grams" is type "mass". Use the 
31666  * static call {@link Measurement.getAvailableUnits}
31667  * to find out what units this version of ilib supports.
31668  *  
31669  * @return {string} the name of the type of this measurement
31670  */
31671 VolumeUnit.prototype.getMeasure = function() {
31672 	return "volume";
31673 };
31674 
31675 /**
31676  * Return a new measurement instance that is converted to a new
31677  * measurement unit. Measurements can only be converted
31678  * to measurements of the same type.<p>
31679  *  
31680  * @param {string} to The name of the units to convert to
31681  * @return {Measurement|undefined} the converted measurement
31682  * or undefined if the requested units are for a different
31683  * measurement type 
31684  */
31685 VolumeUnit.prototype.convert = function(to) {
31686 	if (!to || typeof(VolumeUnit.ratios[this.normalizeUnits(to)]) === 'undefined') {
31687 		return undefined;
31688 	}
31689 	return new VolumeUnit({
31690 		unit: to,
31691 		amount: this
31692 	});
31693 };
31694 
31695 VolumeUnit.aliases = {
31696     "US gal": "gallon",
31697     "US gallon": "gallon",
31698     "US Gal": "gallon",
31699     "US Gallons": "gallon",
31700     "Gal(US)": "gallon",
31701     "gal(US)": "gallon",
31702     "gallon": "gallon",
31703     "quart": "quart",
31704     "US quart": "quart",
31705     "US quarts": "quart",
31706     "US Quart": "quart",
31707     "US Quarts": "quart",
31708     "US qt": "quart",
31709     "Qt(US)": "quart",
31710     "qt(US)": "quart",
31711     "US pint": "pint",
31712     "US Pint": "pint",
31713     "pint": "pint",
31714     "pint(US)": "pint",
31715     "Pint(US)": "pint",
31716     "US cup": "cup",
31717     "US Cup": "cup",
31718     "cup(US)": "cup",
31719     "Cup(US)": "cup",
31720     "cup": "cup",
31721     "us ounce": "us ounce",
31722     "US ounce": "us ounce",
31723     "℥": "us ounce",
31724     "US Oz": "us ounce",
31725     "oz(US)": "us ounce",
31726     "Oz(US)": "us ounce",
31727     "US tbsp": "tbsp",
31728     "tbsp": "tbsp",
31729     "tbsp(US)": "tbsp",
31730     "US tablespoon": "tbsp",
31731     "US tsp": "tsp",
31732     "tsp(US)": "tsp",
31733     "tsp": "tsp",
31734     "Cubic meter": "cubic meter",
31735     "cubic meter": "cubic meter",
31736     "Cubic metre": "cubic meter",
31737     "cubic metre": "cubic meter",
31738     "m3": "cubic meter",
31739     "Liter": "liter",
31740     "Liters": "liter",
31741     "liter": "liter",
31742     "L": "liter",
31743     "l": "liter",
31744     "Milliliter": "milliliter",
31745     "ML": "milliliter",
31746     "ml": "milliliter",
31747     "milliliter": "milliliter",
31748     "mL": "milliliter",
31749     "Imperial gal": "imperial gallon",
31750     "imperial gallon": "imperial gallon",
31751     "Imperial gallon": "imperial gallon",
31752     "gallon(imperial)": "imperial gallon",
31753     "gal(imperial)": "imperial gallon",
31754     "Imperial quart": "imperial quart",
31755     "imperial quart": "imperial quart",
31756     "Imperial Quart": "imperial quart",
31757     "IMperial qt": "imperial quart",
31758     "qt(Imperial)": "imperial quart",
31759     "quart(imperial)": "imperial quart",
31760     "Imperial pint": "imperial pint",
31761     "imperial pint": "imperial pint",
31762     "pint(Imperial)": "imperial pint",
31763     "imperial oz": "imperial ounce",
31764     "imperial ounce": "imperial ounce",
31765     "Imperial Ounce": "imperial ounce",
31766     "Imperial tbsp": "imperial tbsp",
31767     "imperial tbsp": "imperial tbsp",
31768     "tbsp(Imperial)": "imperial tbsp",
31769     "Imperial tsp": "imperial tsp",
31770     "imperial tsp": "imperial tsp",
31771     "tsp(Imperial)": "imperial tsp",
31772     "Cubic foot": "cubic foot",
31773     "cubic foot": "cubic foot",
31774     "Cubic Foot": "cubic foot",
31775     "Cubic feet": "cubic foot",
31776     "cubic Feet": "cubic foot",
31777     "cubic ft": "cubic foot",
31778     "ft3": "cubic foot",
31779     "Cubic inch": "cubic inch",
31780     "Cubic inches": "cubic inch",
31781     "cubic inches": "cubic inch",
31782     "cubic inch": "cubic inch",
31783     "cubic in": "cubic inch",
31784     "cu in": "cubic inch",
31785     "cu inch": "cubic inch",
31786     "inch³": "cubic inch",
31787     "in³": "cubic inch",
31788     "inch^3": "cubic inch",
31789     "in^3": "cubic inch",
31790     "c.i": "cubic inch",
31791     "CI": "cubic inch",
31792     "cui": "cubic inch"
31793 };
31794 
31795 /**
31796  * Convert a volume to another measure.
31797  * @static
31798  * @param to {string} unit to convert to
31799  * @param from {string} unit to convert from
31800  * @param volume {number} amount to be convert
31801  * @returns {number|undefined} the converted amount
31802  */
31803 VolumeUnit.convert = function(to, from, volume) {
31804     from = VolumeUnit.aliases[from] || from;
31805     to = VolumeUnit.aliases[to] || to;
31806 	var fromRow = VolumeUnit.ratios[from];
31807 	var toRow = VolumeUnit.ratios[to];
31808 	if (typeof(from) === 'undefined' || typeof(to) === 'undefined') {
31809 		return undefined;
31810 	}	
31811 	var result = volume * fromRow[toRow[0]];
31812     return result;
31813 };
31814 
31815 /**
31816  * @private
31817  * @static
31818  */
31819 VolumeUnit.getMeasures = function () {
31820 	var ret = [];
31821 	for (var m in VolumeUnit.ratios) {
31822 		ret.push(m);
31823 	}
31824 	return ret;
31825 };
31826 VolumeUnit.metricSystem = {
31827     "milliliter": 10,
31828     "liter": 11,
31829     "cubic meter": 12
31830 };
31831 VolumeUnit.imperialSystem = {
31832     "imperial tsp": 13,
31833     "imperial tbsp": 14,
31834     "imperial ounce": 15,
31835     "imperial pint": 16,
31836     "imperial quart": 17,
31837     "imperial gallon": 18
31838 };
31839 VolumeUnit.uscustomarySystem = {
31840     "tsp": 1,
31841     "tbsp": 2,
31842     "cubic inch": 3,
31843     "us ounce": 4,
31844     "cup": 5,
31845     "pint": 6,
31846     "quart": 7,
31847     "gallon": 8,
31848     "cubic foot": 9
31849 };
31850 
31851 VolumeUnit.metricToUScustomary = {
31852     "milliliter": "tsp",
31853     "liter": "quart",
31854     "cubic meter": "cubic foot"
31855 };
31856 VolumeUnit.metricToImperial = {
31857     "milliliter": "imperial tsp",
31858     "liter": "imperial quart",
31859     "cubic meter": "imperial gallon"
31860 };
31861 
31862 VolumeUnit.imperialToMetric = {
31863     "imperial tsp": "milliliter",
31864     "imperial tbsp": "milliliter",
31865     "imperial ounce": "milliliter",
31866     "imperial pint": "liter",
31867     "imperial quart": "liter",
31868     "imperial gallon": "cubic meter"
31869 };
31870 VolumeUnit.imperialToUScustomary = {
31871     "imperial tsp": "tsp",
31872     "imperial tbsp": "tbsp",
31873     "imperial ounce": "us ounce",
31874     "imperial pint": "pint",
31875     "imperial quart": "quart",
31876     "imperial gallon": "gallon"
31877 };
31878 
31879 VolumeUnit.uScustomaryToImperial = {
31880     "tsp": "imperial tsp",
31881     "tbsp": "imperial tbsp",
31882     "cubic inch": "imperial tbsp",
31883     "us ounce": "imperial ounce",
31884     "cup": "imperial ounce",
31885     "pint": "imperial pint",
31886     "quart": "imperial quart",
31887     "gallon": "imperial gallon",
31888     "cubic foot": "imperial gallon"
31889 };
31890 VolumeUnit.uScustomarylToMetric = {
31891     "tsp": "milliliter",
31892     "tbsp": "milliliter",
31893     "cubic inch": "milliliter",
31894     "us ounce": "milliliter",
31895     "cup": "milliliter",
31896     "pint": "liter",
31897     "quart": "liter",
31898     "gallon": "cubic meter",
31899     "cubic foot": "cubic meter"
31900 };
31901 
31902 /**
31903  * Localize the measurement to the commonly used measurement in that locale. For example
31904  * If a user's locale is "en-US" and the measurement is given as "60 kmh", 
31905  * the formatted number should be automatically converted to the most appropriate 
31906  * measure in the other system, in this case, mph. The formatted result should
31907  * appear as "37.3 mph". 
31908  * 
31909  * @param {string} locale current locale string
31910  * @returns {Measurement} a new instance that is converted to locale
31911  */
31912 VolumeUnit.prototype.localize = function(locale) {
31913 	var to;
31914 	if (locale === "en-US") {
31915 		to = VolumeUnit.metricToUScustomary[this.unit] ||
31916 		    VolumeUnit.imperialToUScustomary[this.unit] ||
31917 		    this.unit;
31918 	} else if (locale === "en-GB") {
31919 		to = VolumeUnit.metricToImperial[this.unit] ||
31920 		    VolumeUnit.uScustomaryToImperial[this.unit] ||
31921 		    this.unit;
31922 	} else {
31923 		to = VolumeUnit.uScustomarylToMetric[this.unit] ||
31924 		    VolumeUnit.imperialToUScustomary[this.unit] ||
31925 		    this.unit;
31926 	}
31927 	return new VolumeUnit({
31928 	    unit: to,
31929 	    amount: this
31930 	});
31931 };
31932 
31933 /**
31934  * Scale the measurement unit to an acceptable level. The scaling
31935  * happens so that the integer part of the amount is as small as
31936  * possible without being below zero. This will result in the 
31937  * largest units that can represent this measurement without
31938  * fractions. Measurements can only be scaled to other measurements 
31939  * of the same type.
31940  * 
31941  * @param {string=} measurementsystem system to use (uscustomary|imperial|metric),
31942  * or undefined if the system can be inferred from the current measure
31943  * @return {Measurement} a new instance that is scaled to the 
31944  * right level
31945  */
31946 VolumeUnit.prototype.scale = function(measurementsystem) {
31947     var fromRow = VolumeUnit.ratios[this.unit];
31948     var mSystem;
31949 
31950     if (measurementsystem === "metric"|| (typeof(measurementsystem) === 'undefined'
31951         && typeof(VolumeUnit.metricSystem[this.unit]) !== 'undefined')) {
31952         mSystem = VolumeUnit.metricSystem;
31953     } else if (measurementsystem === "uscustomary" || (typeof(measurementsystem) === 'undefined'
31954         && typeof(VolumeUnit.uscustomarySystem[this.unit]) !== 'undefined')) {
31955         mSystem = VolumeUnit.uscustomarySystem;
31956     } else if (measurementsystem === "imperial"|| (typeof(measurementsystem) === 'undefined'
31957         && typeof(VolumeUnit.imperialSystem[this.unit]) !== 'undefined')) {
31958         mSystem = VolumeUnit.imperialSystem;
31959     }
31960 
31961     var volume = this.amount;
31962     var munit = this.unit;
31963 
31964     volume = 18446744073709551999;
31965     
31966     for (var m in mSystem) {
31967     	var tmp = this.amount * fromRow[mSystem[m]];
31968         if (tmp >= 1 && tmp < volume) {
31969         	volume = tmp;
31970 	        munit = m;
31971         }
31972     }
31973     
31974     return new VolumeUnit({
31975         unit: munit,
31976         amount: volume
31977     });
31978 };
31979 
31980 //register with the factory method
31981 Measurement._constructors["volume"] = VolumeUnit;
31982 
31983 
31984 
31985 /*< MeasurementFactory.js */
31986 /*
31987  * MeasurementFactory.js - Function to instantiate the appropriate subclasses of
31988  * the Measurement class.
31989  *
31990  * Copyright © 2015, JEDLSoft
31991  *
31992  * Licensed under the Apache License, Version 2.0 (the "License");
31993  * you may not use this file except in compliance with the License.
31994  * You may obtain a copy of the License at
31995  *
31996  *     http://www.apache.org/licenses/LICENSE-2.0
31997  *
31998  * Unless required by applicable law or agreed to in writing, software
31999  * distributed under the License is distributed on an "AS IS" BASIS,
32000  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
32001  *
32002  * See the License for the specific language governing permissions and
32003  * limitations under the License.
32004  */
32005 
32006 /*
32007 !depends
32008 UnknownUnit.js
32009 AreaUnit.js
32010 DigitalStorageUnit.js
32011 EnergyUnit.js
32012 FuelConsumptionUnit.js
32013 LengthUnit.js
32014 MassUnit.js
32015 TemperatureUnit.js
32016 TimeUnit.js
32017 VelocityUnit.js
32018 VolumeUnit.js
32019 Measurement.js
32020 */
32021 
32022 // TODO: make these dependencies dynamic or at least generate them in the build
32023 // These will each add themselves to Measurement._constructors[]
32024 
32025 
32026 /**
32027  * Create a measurement subclass instance based on a particular measure
32028  * required. The measurement is immutable once
32029  * it is created, but it can be converted to other measurements later.<p>
32030  *
32031  * The options may contain any of the following properties:
32032  *
32033  * <ul>
32034  * <li><i>amount</i> - either a numeric amount for this measurement given
32035  * as a number of the specified units, or another Measurement instance
32036  * to convert to the requested units. If converting to new units, the type
32037  * of measure between the other instance's units and the current units
32038  * must be the same. That is, you can only convert one unit of mass to
32039  * another. You cannot convert a unit of mass into a unit of length.
32040  *
32041  * <li><i>unit</i> - units of this measurement. Use the
32042  * static call {@link MeasurementFactory.getAvailableUnits}
32043  * to find out what units this version of ilib supports. If the given unit
32044  * is not a base unit, the amount will be normalized to the number of base units
32045  * and stored as that number of base units.
32046  * For example, if an instance is constructed with 1 kg, this will be converted
32047  * automatically into 1000 g, as grams are the base unit and kg is merely a
32048  * commonly used scale of grams. 
32049  * </ul>
32050  *
32051  * Here are some examples of converting a length into new units. 
32052  * The first method is via this factory function by passing the old measurement 
32053  * in as the "amount" property.<p>
32054  * 
32055  * <pre>
32056  * var measurement1 = MeasurementFactory({
32057  *   amount: 5,
32058  *   units: "kilometers"
32059  * });
32060  * var measurement2 = MeasurementFactory({
32061  *   amount: measurement1,
32062  *   units: "miles"
32063  * });
32064  * </pre>
32065  * 
32066  * The value in measurement2 will end up being about 3.125 miles.<p>
32067  * 
32068  * The second method uses the convert method.<p>
32069  * 
32070  * <pre>
32071  * var measurement1 = MeasurementFactory({
32072  *   amount: 5,
32073  *   units: "kilometers"
32074  * });
32075  * var measurement2 = measurement1.convert("miles");
32076  * });
32077  * </pre>
32078  *
32079  * The value in measurement2 will again end up being about 3.125 miles.
32080  * 
32081  * @static
32082  * @param {Object=} options options that control the construction of this instance
32083  */
32084 var MeasurementFactory = function(options) {
32085 	if (!options || typeof(options.unit) === 'undefined') {
32086 		return undefined;
32087 	}
32088 
32089 	var measure = undefined;
32090 
32091 	for (var c in Measurement._constructors) {
32092 		var measurement = Measurement._constructors[c];
32093 		if (typeof(measurement.aliases[options.unit]) !== 'undefined') {
32094 			measure = c;
32095 			break;
32096 		}
32097 	}
32098 
32099 	if (!measure || typeof(measure) === 'undefined') {
32100 		return new UnknownUnit({
32101 			unit: options.unit,
32102 			amount: options.amount
32103 		});
32104 	} else {
32105 		return new Measurement._constructors[measure](options);
32106 	}
32107 };
32108 
32109 /**
32110  * Return a list of all possible units that this version of ilib supports.
32111  * Typically, the units are given as their full names in English. Unit names
32112  * are case-insensitive.
32113  *
32114  * @static
32115  * @return {Array.<string>} an array of strings containing names of measurement 
32116  * units available
32117  */
32118 MeasurementFactory.getAvailableUnits = function () {
32119 	var units = [];
32120 	for (var c in Measurement._constructors) {
32121 		var measure = Measurement._constructors[c];
32122 		units = units.concat(measure.getMeasures());
32123 	}
32124 	return units;
32125 };
32126 
32127 
32128 
32129 /*< UnitFmt.js */
32130 /*
32131  * UnitFmt.js - Unit formatter class
32132  * 
32133  * Copyright © 2014-2015, JEDLSoft
32134  *
32135  * Licensed under the Apache License, Version 2.0 (the "License");
32136  * you may not use this file except in compliance with the License.
32137  * You may obtain a copy of the License at
32138  *
32139  *     http://www.apache.org/licenses/LICENSE-2.0
32140  *
32141  * Unless required by applicable law or agreed to in writing, software
32142  * distributed under the License is distributed on an "AS IS" BASIS,
32143  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
32144  *
32145  * See the License for the specific language governing permissions and
32146  * limitations under the License.
32147  */
32148 
32149 /*
32150 !depends 
32151 ilib.js 
32152 Locale.js 
32153 ResBundle.js 
32154 LocaleInfo.js
32155 IString.js
32156 NumFmt.js
32157 Utils.js
32158 */
32159 
32160 // !data unitfmt
32161 
32162 
32163 
32164 /**
32165  * @class
32166  * Create a new unit formatter instance. The unit formatter is immutable once
32167  * it is created, but can format as many different strings with different values
32168  * as needed with the same options. Create different unit formatter instances 
32169  * for different purposes and then keep them cached for use later if you have 
32170  * more than one unit string to format.<p>
32171  * 
32172  * The options may contain any of the following properties:
32173  * 
32174  * <ul>
32175  * <li><i>locale</i> - locale to use when formatting the units. The locale also
32176  * controls the translation of the names of the units. If the locale is
32177  * not specified, then the default locale of the app or web page will be used.
32178  * 
32179  * <li><i>autoScale</i> - when true, automatically scale the amount to get the smallest
32180  * number greater than 1, where possible, possibly by converting units within the locale's
32181  * measurement system. For example, if the current locale is "en-US", and we have
32182  * a measurement containing 278 fluid ounces, then the number "278" can be scaled down
32183  * by converting the units to a larger one such as gallons. The scaled size would be
32184  * 2.17188 gallons. Since iLib does not have a US customary measure larger than gallons,
32185  * it cannot scale it down any further. If the amount is less than the smallest measure
32186  * already, it cannot be scaled down any further and no autoscaling will be applied.
32187  * Default for the autoScale property is "true", so it only needs to be specified when
32188  * you want to turn off autoscaling.
32189  * 
32190  * <li><i>autoConvert</i> - automatically convert the units to the nearest appropriate
32191  * measure of the same type in the measurement system used by the locale. For example, 
32192  * if a measurement of length is given in meters, but the current locale is "en-US" 
32193  * which uses the US Customary system, then the nearest appropriate measure would be 
32194  * "yards", and the amount would be converted from meters to yards automatically before
32195  * being formatted. Default for the autoConvert property is "true", so it only needs to 
32196  * be specified when you want to turn off autoconversion.
32197  * 
32198  * <li><i>maxFractionDigits</i> - the maximum number of digits that should appear in the
32199  * formatted output after the decimal. A value of -1 means unlimited, and 0 means only print
32200  * the integral part of the number.
32201  * 
32202  * <li><i>minFractionDigits</i> - the minimum number of fractional digits that should
32203  * appear in the formatted output. If the number does not have enough fractional digits
32204  * to reach this minimum, the number will be zero-padded at the end to get to the limit.
32205  * 
32206  * <li><i>roundingMode</i> - When the maxFractionDigits or maxIntegerDigits is specified,
32207  * this property governs how the least significant digits are rounded to conform to that
32208  * maximum. The value of this property is a string with one of the following values:
32209  * <ul>
32210  *   <li><i>up</i> - round away from zero
32211  *   <li><i>down</i> - round towards zero. This has the effect of truncating the number
32212  *   <li><i>ceiling</i> - round towards positive infinity
32213  *   <li><i>floor</i> - round towards negative infinity
32214  *   <li><i>halfup</i> - round towards nearest neighbour. If equidistant, round up.
32215  *   <li><i>halfdown</i> - round towards nearest neighbour. If equidistant, round down.
32216  *   <li><i>halfeven</i> - round towards nearest neighbour. If equidistant, round towards the even neighbour
32217  *   <li><i>halfodd</i> - round towards nearest neighbour. If equidistant, round towards the odd neighbour
32218  * </ul>
32219  * 
32220  * <li><i>onLoad</i> - a callback function to call when the date format object is fully 
32221  * loaded. When the onLoad option is given, the UnitFmt object will attempt to
32222  * load any missing locale data using the ilib loader callback.
32223  * When the constructor is done (even if the data is already preassembled), the 
32224  * onLoad function is called with the current instance as a parameter, so this
32225  * callback can be used with preassembled or dynamic loading or a mix of the two.
32226  * 
32227  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
32228  * asynchronously. If this option is given as "false", then the "onLoad"
32229  * callback must be given, as the instance returned from this constructor will
32230  * not be usable for a while.
32231  *  
32232  * <li><i>loadParams</i> - an object containing parameters to pass to the 
32233  * loader callback function when locale data is missing. The parameters are not
32234  * interpretted or modified in any way. They are simply passed along. The object 
32235  * may contain any property/value pairs as long as the calling code is in
32236  * agreement with the loader callback function as to what those parameters mean.
32237  * </ul>
32238  * 
32239  * Here is an example of how you might use the unit formatter to format a string with
32240  * the correct units.<p>
32241  * 
32242  *  
32243  * @constructor
32244  * @param {Object} options options governing the way this date formatter instance works
32245  */
32246 var UnitFmt = function(options) {
32247 	var sync = true, 
32248 		loadParams = undefined;
32249 	
32250     this.length = "long";
32251     this.scale  = true;
32252     this.measurementType = 'undefined';
32253     this.convert = true;
32254 	this.locale = new Locale();
32255 
32256     if (options) {
32257     	if (options.locale) {
32258     		this.locale = (typeof(options.locale) === 'string') ? new Locale(options.locale) : options.locale;
32259     	}
32260 
32261     	if (typeof(options.sync) === 'boolean') {
32262     		sync = options.sync;
32263     	}
32264 
32265     	if (typeof(options.loadParams) !== 'undefined') {
32266     		loadParams = options.loadParams;
32267     	}
32268 
32269     	if (options.length) {
32270     		this.length = options.length;
32271     	}
32272 
32273     	if (typeof(options.autoScale) === 'boolean') {
32274     		this.scale = options.autoScale;
32275     	}
32276 
32277     	if (typeof(options.autoConvert) === 'boolean') {
32278     		this.convert = options.autoConvert;
32279     	}
32280         
32281         if (typeof(options.useNative) === 'boolean') {
32282     		this.useNative = options.useNative;
32283     	}
32284 
32285     	if (options.measurementSystem) {
32286     		this.measurementSystem = options.measurementSystem;
32287     	}
32288         
32289         if (typeof (options.maxFractionDigits) === 'number') {
32290             /** 
32291              * @private
32292              * @type {number|undefined} 
32293              */
32294             this.maxFractionDigits = options.maxFractionDigits;
32295         }
32296         if (typeof (options.minFractionDigits) === 'number') {
32297             /** 
32298              * @private
32299              * @type {number|undefined} 
32300              */
32301             this.minFractionDigits = options.minFractionDigits;
32302         }
32303         /** 
32304          * @private
32305          * @type {string} 
32306          */
32307         this.roundingMode = options.roundingMode;
32308     }
32309 
32310     if (!UnitFmt.cache) {
32311     	UnitFmt.cache = {};
32312     }
32313 
32314 	Utils.loadData({
32315 		object: UnitFmt, 
32316 		locale: this.locale, 
32317 		name: "unitfmt.json", 
32318 		sync: sync, 
32319 		loadParams: loadParams, 
32320 		callback: ilib.bind(this, function (format) {                      
32321 			var formatted = format;
32322 			this.template = formatted["unitfmt"][this.length];
32323 			
32324 			new NumFmt({
32325 	    		locale: this.locale,
32326 	    		useNative: this.useNative,
32327 	            maxFractionDigits: this.maxFractionDigits,
32328 	            minFractionDigits: this.minFractionDigits,
32329 	            roundingMode: this.roundingMode,
32330 	            sync: sync,
32331 	            loadParams: loadParams,
32332 	            onLoad: ilib.bind(this, function (numfmt) {
32333 	            	this.numFmt = numfmt;
32334 	            	
32335 	    			if (options && typeof(options.onLoad) === 'function') {
32336 	    				options.onLoad(this);
32337 	    			}
32338 	            })
32339 	    	});
32340 		})
32341 	});
32342 };
32343 
32344 UnitFmt.prototype = {
32345 	
32346 	/**
32347 	 * Return the locale used with this formatter instance.
32348 	 * @return {Locale} the Locale instance for this formatter
32349 	 */
32350 	getLocale: function() {
32351 		return this.locale;
32352 	},
32353 	
32354 	/**
32355 	 * Return the template string that is used to format date/times for this
32356 	 * formatter instance. This will work, even when the template property is not explicitly 
32357 	 * given in the options to the constructor. Without the template option, the constructor 
32358 	 * will build the appropriate template according to the options and use that template
32359 	 * in the format method. 
32360 	 * 
32361 	 * @return {string} the format template for this formatter
32362 	 */
32363 	getTemplate: function() {
32364 		return this.template;
32365 	},
32366 	
32367 	/**
32368 	 * Convert this formatter to a string representation by returning the
32369 	 * format template. This method delegates to getTemplate.
32370 	 * 
32371 	 * @return {string} the format template
32372 	 */
32373 	toString: function() {
32374 		return this.getTemplate();
32375 	},
32376     
32377 	/**
32378 	 * Return whether or not this formatter will auto-scale the units while formatting.
32379 	 * @returns {boolean} true if auto-scaling is turned on
32380 	 */
32381     getScale: function() {
32382         return this.scale;
32383     },
32384 
32385     /**
32386      * Return the measurement system that is used for this formatter.
32387      * @returns {string} the measurement system used in this formatter
32388      */
32389     getMeasurementSystem: function() {
32390         return this.measurementSystem;
32391     },
32392 
32393 	/**
32394 	 * Format a particular unit instance according to the settings of this
32395 	 * formatter object.
32396 	 * 
32397 	 * @param {Measurement} measurement measurement to format	 
32398 	 * @return {string} the formatted version of the given date instance
32399 	 */
32400     format: function (measurement) {
32401     	var u = this.convert ? measurement.localize(this.locale.getSpec()) : measurement;
32402     	u = this.scale ? u.scale(this.measurementSystem) : u;
32403     	var formatted = new IString(this.template[u.getUnit()]);
32404     	// make sure to use the right plural rules
32405     	formatted.setLocale(this.locale, true, undefined, undefined);
32406     	formatted = formatted.formatChoice(u.amount,{n:this.numFmt.format(u.amount)});
32407     	return formatted.length > 0 ? formatted : u.amount +" " + u.unit;
32408     }
32409 };
32410 
32411 
32412 /*< Charset.js */
32413 /*
32414  * Charset.js - Return information about a particular character set
32415  * 
32416  * Copyright © 2014-2015, JEDLSoft
32417  *
32418  * Licensed under the Apache License, Version 2.0 (the "License");
32419  * you may not use this file except in compliance with the License.
32420  * You may obtain a copy of the License at
32421  *
32422  *     http://www.apache.org/licenses/LICENSE-2.0
32423  *
32424  * Unless required by applicable law or agreed to in writing, software
32425  * distributed under the License is distributed on an "AS IS" BASIS,
32426  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
32427  *
32428  * See the License for the specific language governing permissions and
32429  * limitations under the License.
32430  */
32431 
32432 // !depends ilib.js Utils.js
32433 // !data charsetaliases charset/ISO-8859-1 charset/ISO-8859-15 charset/UTF-8
32434 
32435 
32436 /**
32437  * @class
32438  * Create a new character set info instance. Charset instances give information about
32439  * a particular character set, such as whether or not it is single byte or multibyte,
32440  * and which languages commonly use that charset.<p>
32441  * 
32442  * The optional options object holds extra parameters if they are necessary. The
32443  * current list of supported options are:
32444  * 
32445  * <ul>
32446  * <li><i>name</i> - the name of the charset. This can be given as any commonly
32447  * used name for the character set, which is normalized to a standard IANA name 
32448  * before its info is loaded. If a name is not given,
32449  * this class will return information about the base character set of Javascript,
32450  * which is currently Unicode as encoded in UTF-16.
32451  * 
32452  * <li><i>onLoad</i> - a callback function to call when this object is fully 
32453  * loaded. When the onLoad option is given, this class will attempt to
32454  * load any missing data using the ilib loader callback.
32455  * When the constructor is done (even if the data is already preassembled), the 
32456  * onLoad function is called with the current instance as a parameter, so this
32457  * callback can be used with preassembled or dynamic loading or a mix of the two.
32458  * 
32459  * <li><i>sync</i> - tell whether to load any missing data synchronously or 
32460  * asynchronously. If this option is given as "false", then the "onLoad"
32461  * callback must be given, because the instance returned from this constructor will
32462  * not be usable for a while.
32463  *
32464  * <li><i>loadParams</i> - an object containing parameters to pass to the 
32465  * loader callback function when data is missing. The parameters are not
32466  * interpretted or modified in any way. They are simply passed along. The object 
32467  * may contain any property/value pairs as long as the calling code is in
32468  * agreement with the loader callback function as to what those parameters mean.
32469  * </ul>
32470  * 
32471  * If this copy of ilib is pre-assembled and all the data is already available, 
32472  * or if the data was already previously loaded, then this constructor will call
32473  * the onLoad callback immediately when the initialization is done. 
32474  * If the onLoad option is not given, this class will only attempt to load any
32475  * missing data synchronously.
32476  * 
32477  * Depends directive: !depends charset.js
32478  * 
32479  * @constructor
32480  * @see {ilib.setLoaderCallback} for information about registering a loader callback instance
32481  * @param {Object=} options options which govern the construction of this instance
32482  */
32483 var Charset = function(options) {
32484 	var sync = true,
32485 	    loadParams = undefined;
32486 	this.originalName = "UTF-8";
32487 	
32488 	if (options) {
32489 		if (typeof(options.name) !== 'undefined') {
32490 			this.originalName = options.name;
32491 		}
32492 		
32493 		if (typeof(options.sync) !== 'undefined') {
32494 			sync = (options.sync == true);
32495 		}
32496 		
32497 		if (typeof(options.loadParams) !== 'undefined') {
32498 			loadParams = options.loadParams;
32499 		}
32500 	}
32501 
32502 	if (!Charset.cache) {
32503 		Charset.cache = {};
32504 	}
32505 	
32506 	// default data. A majority of charsets use this info
32507 	this.info = {
32508 		description: "default",
32509 		min: 1,
32510 		max: 1,
32511 		bigendian: true,
32512 		scripts: ["Latn"],
32513 		locales: ["*"]
32514 	};
32515 
32516 	Utils.loadData({
32517 		object: Charset, 
32518 		locale: "-",
32519 		nonlocale: true,
32520 		name: "charsetaliases.json", 
32521 		sync: sync,
32522 		loadParams: loadParams, 
32523 		callback: ilib.bind(this, function (info) {
32524 			// first map the given original name to one of the standardized IANA names
32525 			if (info) {
32526 				// recognize better by getting rid of extraneous crap and upper-casing
32527 				// it so that the match is case-insensitive
32528 				var n = this.originalName.replace(/[-_,:\+\.\(\)]/g, '').toUpperCase();
32529 				this.name = info[n];
32530 			}
32531 			if (!this.name) {
32532 				this.name = this.originalName;
32533 			}
32534 			Utils.loadData({
32535 				object: Charset, 
32536 				locale: "-",
32537 				nonlocale: true,
32538 				name: "charset/" + this.name + ".json", 
32539 				sync: sync, 
32540 				loadParams: loadParams, 
32541 				callback: ilib.bind(this, function (info) {
32542 					if (info) {
32543 						ilib.extend(this.info, info);	
32544 					}
32545 					if (options && typeof(options.onLoad) === 'function') {
32546 						options.onLoad(this);
32547 					}
32548 				})
32549 			});
32550 		})
32551 	});
32552 };
32553 
32554 Charset.prototype = {
32555     /**
32556      * Return the standard normalized name of this charset.  The list of standard names 
32557      * comes from the IANA registry of character set names at 
32558      * <a href="http://www.iana.org/assignments/character-sets/character-sets.xhtml">http://www.iana.org/assignments/character-sets/character-sets.xhtml</a>.
32559      * 
32560      * @returns {string} the name of the charset
32561      */
32562     getName: function () {
32563     	return this.name;	
32564     },
32565     
32566     /**
32567      * Return the original name that this instance was constructed with before it was
32568      * normalized to the standard name returned by {@link #getName}.
32569      * 
32570      * @returns {String} the original name that this instance was constructed with
32571      */
32572     getOriginalName: function() {
32573     	return this.originalName;
32574     },
32575     
32576     /**
32577      * Return a short description of the character set.
32578      * 
32579      * @returns {string} a description of the character set
32580      */
32581     getDescription: function() {
32582     	return this.info.description || this.getName();
32583     },
32584     
32585     /**
32586      * Return the smallest number of bytes that a single character in this charset
32587      * could use. For most charsets, this is 1, but for some charsets such as Unicode
32588      * encoded in UTF-16, this may be 2 or more.
32589      * @returns {number} the smallest number of bytes that a single character in
32590      * this charset uses
32591      */
32592     getMinCharWidth: function () {
32593     	return this.info.min;
32594     },
32595     
32596     /**
32597      * Return the largest number of bytes that a single character in this charset
32598      * could use.
32599      * @returns {number} the largest number of bytes that a single character in
32600      * this charset uses
32601      */
32602     getMaxCharWidth: function () {
32603     	return this.info.max;
32604     },
32605     
32606     /**
32607      * Return true if this is a multibyte character set, or false for a fixed
32608      * width character set. A multibyte character set is one in which the characters
32609      * have a variable width. That is, one character may use 1 byte and a different
32610      * character might use 2 or 3 bytes.
32611      * 
32612      * @returns {boolean} true if this is a multibyte charset, or false otherwise
32613      */
32614     isMultibyte: function() {
32615     	return this.getMaxCharWidth() > this.getMinCharWidth();
32616     },
32617     
32618     /**
32619      * Return whether or not characters larger than 1 byte use the big endian order
32620      * or little endian.
32621      * 
32622      * @returns {boolean} true if this character set uses big endian order, or false
32623      * otherwise
32624      */
32625     isBigEndian: function() {
32626     	return this.info.bigendian;
32627     },
32628     
32629     /**
32630      * Return an array of ISO script codes whose characters can be encoded with this 
32631      * character set.
32632      * 
32633      * @returns {Array.<string>} an array of ISO script codes supported by this charset
32634      */
32635     getScripts: function() {
32636     	return this.info.scripts;
32637     }
32638 };
32639 
32640 
32641 /*< Charmap.js */
32642 /*
32643  * Charmap.js - A character set mapping class
32644  * 
32645  * Copyright © 2014-2015, JEDLSoft
32646  *
32647  * Licensed under the Apache License, Version 2.0 (the "License");
32648  * you may not use this file except in compliance with the License.
32649  * You may obtain a copy of the License at
32650  *
32651  *     http://www.apache.org/licenses/LICENSE-2.0
32652  *
32653  * Unless required by applicable law or agreed to in writing, software
32654  * distributed under the License is distributed on an "AS IS" BASIS,
32655  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
32656  *
32657  * See the License for the specific language governing permissions and
32658  * limitations under the License.
32659  */
32660 
32661 // !depends ilib.js Utils.js Charset.js JSUtils.js IString.js
32662 
32663 // !data charset/US-ASCII charset/ISO-10646-UCS-2 charset/ISO-10646-UCS-4 charset/ISO-10646-Unicode-Latin1
32664 
32665 
32666 /**
32667  * @class
32668  * Create a new default character set mapping instance. This class is the parent
32669  * class of all of the charmapping subclasses, and only implements basic US-ASCII
32670  * mapping. The subclasses implement all other charsets, some algorithmically, and
32671  * some in a table-based way. Use {@link CharmapFactory} to create the correct
32672  * subclass instance for the desired charmap.<p>
32673  * 
32674  * All mappings are done to or from Unicode in the UTF-16 encoding, which is the base
32675  * character set and encoding used by Javascript itself. In order to convert 
32676  * between two non-Unicode character sets, you must chain two charmap instances together 
32677  * to first map to Unicode and then back to the second charset. <p>
32678  * 
32679  * The options parameter controls which mapping is constructed and its behaviours. The 
32680  * current list of supported options are:
32681  * 
32682  * <ul>
32683  * <li><i>missing</i> - specify what to do if a mapping is missing for a particular
32684  * character. For example, if you are mapping Unicode characters to a particular native
32685  * character set that does not support particular Unicode characters, the mapper will
32686  * follow the behaviour specified in this property. Valid values are:
32687  * <ul>
32688  * <li><i>skip</i> - skip any characters that do not exist in the target charset
32689  * <li><i>placeholder</i> - put a static placeholder character in the output string 
32690  * wherever there is an unknown character in the input string. Use the <i>placeholder</i> 
32691  * parameter to specify which character to use in this case
32692  * <li><i>escape</i> - use an escape sequence to represent the unknown character 
32693  * </ul>
32694  * The default value for the missing property if not otherwise specified is "escape"
32695  * so that information is not lost.
32696  * 
32697  * <li><i>placeholder</i> - specify the placeholder character to use when the 
32698  * mapper cannot map a particular input character to the output string. If this
32699  * option is not specified, then the '?' (question mark) character is used where 
32700  * possible.
32701  * 
32702  * <li><i>escapeStyle</i> - what style of escape sequences should be used to
32703  * escape unknown characters in the input when mapping to native, and what
32704  * style of espcae sequences should be parsed when mapping to Unicode. Valid 
32705  * values are:
32706  * <ul>
32707  * <li><i>html</i> - Escape the characters as HTML entities. This would use
32708  * the standard HTML 5.0 (or later) entity names where possible, and numeric
32709  * entities in all other cases. Eg. an "e" with an acute accent would be 
32710  * "é"
32711  * <li><i>js</i> - Use the Javascript escape style. Eg. an "e" with an acute
32712  * accent would be "\u00E9". This can also be specified as "c#" as
32713  * it uses a similar escape syntax.
32714  * <li><i>c</i> - Use the C/C++ escape style, which is similar to the the
32715  * Javascript style, but uses an "x" in place of the "u". Eg. an "e" with an 
32716  * acute accent would be "\x00E9". This can also be specified as "c++".
32717  * <li><i>java</i> - Use the Java escape style. This is very similar to the
32718  * the Javascript style, but the backslash has to be escaped twice. Eg. an
32719  * "e" with an acute accent would be "\\u00E9". This can also be specified
32720  * as "ruby", as Ruby uses a similar escape syntax with double backslashes.
32721  * <li><i>perl</i> - Use the Perl escape style. Eg. an "e" with an acute
32722  * accent would be "\N{U+00E9}"
32723  * </ul>
32724  * The default if this style is not specified is "js" for Javascript.
32725  * </ul>
32726  * 
32727  * If this copy of ilib is pre-assembled and all the data is already available, 
32728  * or if the data was already previously loaded, then this constructor will call
32729  * the onLoad callback immediately when the initialization is done. 
32730  * If the onLoad option is not given, this class will only attempt to load any
32731  * missing data synchronously.
32732  * 
32733  * @constructor
32734  * @param {Object=} options options which govern the construction of this instance
32735  */
32736 var Charmap = function(options) {
32737 	var sync = true,
32738 	    loadParams = undefined;
32739 	
32740 	this.charset = new Charset({name: "US-ASCII"});
32741 	this.missing = "placeholder";
32742 	this.placeholder = "?";
32743 	this.escapeStyle = "js";
32744 	this.expansionFactor = 1;
32745 	
32746 	if (options) {
32747 		if (typeof(options.placeholder) !== 'undefined') {
32748 			this.placeholder = options.placeholder;
32749 		}
32750 
32751 		var escapes = {
32752 			"html": "html",
32753 			"js": "js",
32754 			"c#": "js",
32755 			"c": "c",
32756 			"c++": "c",
32757 			"java": "java",
32758 			"ruby": "java",
32759 			"perl": "perl"
32760 		};
32761 		
32762 		if (typeof(options.escapeStyle) !== 'undefined') {
32763 			if (typeof(escapes[options.escapeStyle]) !== 'undefined') {
32764 				this.escapeStyle = escapes[options.escapeStyle];
32765 			}
32766 		}
32767 
32768 		if (typeof(options.missing) !== 'undefined') {
32769 			if (options.missing === "skip" || options.missing === "placeholder" || options.missing === "escape") {
32770 				this.missing = options.missing;
32771 			}
32772 		}
32773 	}
32774 	
32775 	this._calcExpansionFactor();
32776 };
32777 
32778 /**
32779  * A place for the algorithmic conversions to register themselves as 
32780  * they are defined.
32781  * 
32782  * @static
32783  * @private
32784  */
32785 Charmap._algorithms = {};
32786 
32787 Charmap.prototype = {
32788     /**
32789      * Return the standard name of this charmap. All charmaps map from
32790      * Unicode to the native charset, so the name returned from this
32791      * function corresponds to the native charset.
32792      * 
32793      * @returns {string} the name of the locale's language in English
32794      */
32795     getName: function () {
32796     	return this.charset.getName();	
32797     },
32798     
32799     /**
32800      * @private
32801      */
32802     writeNative: function (array, start, value) {
32803     	// console.log("Charmap.writeNative: start " + start + " adding " + JSON.stringify(value));
32804     	if (ilib.isArray(value)) { 
32805 	    	for (var i = 0; i < value.length; i++) {
32806 	    		array[start+i] = value[i];
32807 	    	}
32808 	    	
32809 	    	return value.length;
32810     	} else {
32811     		array[start] = value;
32812     		return 1;
32813     	}
32814     },
32815     
32816     /**
32817      * @private
32818      */
32819     writeNativeString: function (array, start, string) {
32820     	// console.log("Charmap.writeNativeString: start " + start + " adding " + JSON.stringify(string));
32821     	for (var i = 0; i < string.length; i++) {
32822     		array[start+i] = string.charCodeAt(i);
32823     	}
32824     	return string.length;
32825     },
32826     
32827     /**
32828      * @private
32829      */
32830     _calcExpansionFactor: function() {
32831     	var factor = 1;
32832     	factor = Math.max(factor, this.charset.getMaxCharWidth());
32833     	switch (this.missing) {
32834     	case "placeholder":
32835     		if (this.placeholder) {
32836     			factor = Math.max(factor, this.placeholder.length);
32837     		}
32838     		break;
32839     	case "escape":
32840     		switch (this.escapeStyle) {
32841 			case "html":
32842 				factor = Math.max(factor, 8); // &#xHHHH;
32843 				break;
32844 			case "c":
32845 				factor = Math.max(factor, 6); // \xHHHH
32846 				break;
32847 			case "perl":
32848 				factor = Math.max(factor, 10); // \N{U+HHHH}
32849 				break;
32850 				
32851 			default:
32852 				factor = Math.max(factor, 6); // \uHHHH
32853 				break;
32854     		}
32855     		break;
32856 		default:
32857 			break;
32858     	}
32859     	
32860     	this.expansionFactor = factor;
32861     },
32862     
32863     /**
32864      * @private
32865      */
32866     dealWithMissingChar: function(c) {
32867     	var seq = "";
32868     	
32869 		switch (this.missing) {
32870 			case "skip":
32871 				// do nothing
32872 				break;
32873 				
32874 			case "escape":
32875 				var num = (typeof(c) === 'string') ? c.charCodeAt(0) : c;
32876 				var bigc = JSUtils.pad(num.toString(16), 4).toUpperCase();
32877 				switch (this.escapeStyle) {
32878 					case "html":
32879 						seq = "&#x" + bigc + ";";
32880 						break;
32881 					case "c":
32882 						seq = "\\x" + bigc;
32883 						break;
32884 					case "java":
32885 						seq = "\\\\u" + bigc;
32886 						break;
32887 					case "perl":
32888 						seq = "\\N{U+" + bigc + "}";
32889 						break;
32890 						
32891 					default:
32892 					case "js":
32893 						seq = "\\u" + bigc;
32894 						break;
32895 				}
32896 				break;
32897 				
32898 			default:
32899 			case "placeholder":
32900 				seq = this.placeholder;
32901 				break;
32902 		}
32903 		
32904 		return seq;
32905     },
32906     
32907     /**
32908      * Map a string to the native character set. This string may be 
32909      * given as an intrinsic Javascript string object or an IString 
32910      * object.
32911      * 
32912      * @param {string|IString} string string to map to a different 
32913      * character set. 
32914      * @return {Uint8Array} An array of bytes representing the string 
32915      * in the native character set
32916      */
32917     mapToNative: function(string) {
32918     	if (!string) {
32919     		return new Uint8Array(0);
32920     	}
32921     	
32922     	if (this.algorithm) {
32923     		return this.algorithm.mapToNative(string);
32924     	}
32925     	
32926     	// the default algorithm is plain old ASCII
32927     	var str = (string instanceof IString) ? string : new IString(string);
32928     	
32929     	// use IString's iterator so that we take care of walking through
32930     	// the code points correctly, including the surrogate pairs
32931     	var c, i = 0, j = 0, it = str.iterator();
32932     	var ret = new Uint8Array(str.length * this.expansionFactor);
32933     	
32934     	while (it.hasNext() && i < ret.length) {
32935     		c = it.next();
32936     		if (c < 127) {
32937     			ret[i++] = c;
32938     		} else {
32939     			i += this.writeNativeString(ret, i, this.dealWithMissingChar(c));
32940     		}
32941     	}
32942 
32943     	return ret;
32944     },
32945     
32946     /**
32947      * Map a native string to the standard Javascript charset of UTF-16. 
32948      * This string may be given as an array of numbers where each number 
32949      * represents a code point in the "from" charset, or as a Uint8Array 
32950      * array of bytes representing the bytes of the string in order.
32951      * 
32952      * @param {Array.<number>|Uint8Array} bytes bytes to map to 
32953      * a Unicode string
32954      * @return {string} A string in the standard Javascript charset UTF-16
32955      */
32956     mapToUnicode: function(bytes) {
32957     	var ret = "";
32958     	var c, i = 0;
32959     	
32960     	while (i < bytes.length) {
32961     		c = bytes[i];
32962     		
32963     		// the default algorithm is plain old ASCII
32964         	if (c < 128) {
32965     			ret += String.fromCharCode(c);
32966     		} else {
32967     			// The byte at "i" wasn't ASCII
32968 				ret += this.dealWithMissingChar(bytes[i++]);
32969     		}
32970     	}
32971 
32972     	return ret;
32973     }
32974 };
32975 
32976 
32977 /*< CharmapTable.js */
32978 /*
32979  * CharmapTable.js - A character set mapping class that maps using trie table
32980  * 
32981  * Copyright © 2014-2015, JEDLSoft
32982  *
32983  * Licensed under the Apache License, Version 2.0 (the "License");
32984  * you may not use this file except in compliance with the License.
32985  * You may obtain a copy of the License at
32986  *
32987  *     http://www.apache.org/licenses/LICENSE-2.0
32988  *
32989  * Unless required by applicable law or agreed to in writing, software
32990  * distributed under the License is distributed on an "AS IS" BASIS,
32991  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
32992  *
32993  * See the License for the specific language governing permissions and
32994  * limitations under the License.
32995  */
32996 
32997 // !depends ilib.js Utils.js Charset.js Charmap.js IString.js
32998 
32999 // !data charmaps/ISO-8859-1 charset/ISO-8859-1
33000 
33001 
33002 /**
33003  * @class
33004  * Create a new character set mapping instance using based on a trie table. Charmap 
33005  * instances map strings to 
33006  * other character sets. The charsets can be of any type, single-byte, multi-byte,
33007  * shifting, etc. <p>
33008  * 
33009  * All mappings are done to or from Unicode in the UTF-16 encoding, which is the base
33010  * character set and encoding used by Javascript itself. In order to convert 
33011  * between two non-Unicode character sets, you must chain two charmap instances together 
33012  * to first map to Unicode and then back to the second charset. <p>
33013  * 
33014  * The options parameter controls which mapping is constructed and its behaviours. The 
33015  * current list of supported options are:
33016  * 
33017  * <ul>
33018  * <li><i>charset</i> - the name of the native charset to map to or from. This can be 
33019  * given as an {@link Charset} instance or as a string that contains any commonly used name 
33020  * for the character set, which is normalized to a standard IANA name. 
33021  * If a name is not given, this class will default to the Western European character 
33022  * set called ISO-8859-15.
33023  * 
33024  * <li><i>missing</i> - specify what to do if a mapping is missing for a particular
33025  * character. For example, if you are mapping Unicode characters to a particular native
33026  * character set that does not support particular Unicode characters, the mapper will
33027  * follow the behaviour specified in this property. Valid values are:
33028  * <ul>
33029  * <li><i>skip</i> - skip any characters that do not exist in the target charset
33030  * <li><i>placeholder</i> - put a static placeholder character in the output string 
33031  * wherever there is an unknown character in the input string. Use the <i>placeholder</i> 
33032  * parameter to specify which character to use in this case
33033  * <li><i>escape</i> - use an escape sequence to represent the unknown character 
33034  * </ul>
33035  * The default value for the missing property if not otherwise specified is "escape"
33036  * so that information is not lost.
33037  * 
33038  * <li><i>placeholder</i> - specify the placeholder character to use when the 
33039  * mapper cannot map a particular input character to the output string. If this
33040  * option is not specified, then the '?' (question mark) character is used where 
33041  * possible.
33042  * 
33043  * <li><i>escapeStyle</i> - what style of escape sequences should be used to
33044  * escape unknown characters in the input when mapping to native, and what
33045  * style of espcae sequences should be parsed when mapping to Unicode. Valid 
33046  * values are:
33047  * <ul>
33048  * <li><i>html</i> - Escape the characters as HTML entities. This would use
33049  * the standard HTML 5.0 (or later) entity names where possible, and numeric
33050  * entities in all other cases. Eg. an "e" with an acute accent would be 
33051  * "é"
33052  * <li><i>js</i> - Use the Javascript escape style. Eg. an "e" with an acute
33053  * accent would be "\u00E9". This can also be specified as "c#" as
33054  * it uses a similar escape syntax.
33055  * <li><i>c</i> - Use the C/C++ escape style, which is similar to the the
33056  * Javascript style, but uses an "x" in place of the "u". Eg. an "e" with an 
33057  * acute accent would be "\x00E9". This can also be specified as "c++".
33058  * <li><i>java</i> - Use the Java escape style. This is very similar to the
33059  * the Javascript style, but the backslash has to be escaped twice. Eg. an
33060  * "e" with an acute accent would be "\\u00E9". This can also be specified
33061  * as "ruby", as Ruby uses a similar escape syntax with double backslashes.
33062  * <li><i>perl</i> - Use the Perl escape style. Eg. an "e" with an acute
33063  * accent would be "\N{U+00E9}"
33064  * </ul>
33065  * The default if this style is not specified is "js" for Javascript.
33066  * 
33067  * <li><i>onLoad</i> - a callback function to call when this object is fully 
33068  * loaded. When the onLoad option is given, this class will attempt to
33069  * load any missing data using the ilib loader callback.
33070  * When the constructor is done (even if the data is already preassembled), the 
33071  * onLoad function is called with the current instance as a parameter, so this
33072  * callback can be used with preassembled or dynamic loading or a mix of the two.
33073  * 
33074  * <li><i>sync</i> - tell whether to load any missing data synchronously or 
33075  * asynchronously. If this option is given as "false", then the "onLoad"
33076  * callback must be given, because the instance returned from this constructor will
33077  * not be usable for a while.
33078  *
33079  * <li><i>loadParams</i> - an object containing parameters to pass to the 
33080  * loader callback function when data is missing. The parameters are not
33081  * interpretted or modified in any way. They are simply passed along. The object 
33082  * may contain any property/value pairs as long as the calling code is in
33083  * agreement with the loader callback function as to what those parameters mean.
33084  * </ul>
33085  * 
33086  * If this copy of ilib is pre-assembled and all the data is already available, 
33087  * or if the data was already previously loaded, then this constructor will call
33088  * the onLoad callback immediately when the initialization is done. 
33089  * If the onLoad option is not given, this class will only attempt to load any
33090  * missing data synchronously.
33091  * 
33092  * @constructor
33093  * @see {ilib.setLoaderCallback} for information about registering a loader callback instance
33094  * @extends Charmap
33095  * @param {Object=} options options which govern the construction of this instance
33096  */
33097 var CharmapTable = function(options) {
33098 	var sync = true,
33099 	    loadParams = undefined;
33100 	
33101 	// console.log("CharmapTable: constructor with options: " + JSON.stringify(options));
33102 	
33103 	this.parent.call(this, options);
33104 	
33105 	if (options) {
33106 		if (typeof(options.charset) === "object") {
33107 			this.charset = options.charset;
33108 		} else if (typeof(options.name) !== 'undefined') {
33109 			this.charset = new Charset({name: options.name});
33110 		}
33111 		
33112 		if (typeof(options.sync) !== 'undefined') {
33113 			sync = (options.sync == true);
33114 		}
33115 		
33116 		if (typeof(options.loadParams) !== 'undefined') {
33117 			loadParams = options.loadParams;
33118 		}
33119 	}
33120 
33121 	if (!this.charset) {
33122 		this.charset = new Charset({name: "ISO-8859-15"});
33123 	}
33124 
33125 	this._calcExpansionFactor();
33126 	
33127 	if (!Charmap.cache) {
33128 		Charmap.cache = {};
33129 	}
33130 
33131 	Utils.loadData({
33132 		object: Charmap, 
33133 		locale: "-",
33134 		nonlocale: true,
33135 		name: "charmaps/" + this.charset.getName() + ".json", 
33136 		sync: sync, 
33137 		loadParams: loadParams, 
33138 		callback: ilib.bind(this, function (mapping) {
33139 			if (!mapping) {
33140 				throw "No mapping found for " + this.charset.getName();
33141 			}
33142 
33143 			/** @type {{from:Object,to:Object}} */
33144 			this.map = mapping;
33145 			if (options && typeof(options.onLoad) === 'function') {
33146 				options.onLoad(this);
33147 			}
33148 		})
33149 	});
33150 };
33151 
33152 CharmapTable.prototype = new Charmap();
33153 CharmapTable.prototype.parent = Charmap;
33154 CharmapTable.prototype.constructor = CharmapTable;
33155 
33156 /**
33157  * Walk a trie to find the value for the current position in the given array.
33158  * @private
33159  */
33160 CharmapTable.prototype._trieWalk = function(trie, array, start) {
33161 	function isValue(node) {
33162 		return (typeof(node) === 'string' || typeof(node) === 'number' ||
33163 			(typeof(node) === 'object' && ilib.isArray(node)));
33164 	}
33165 	
33166 	var lastLeaf = undefined,
33167 		i = start,
33168 		trienode = trie;
33169 	
33170 	while (i < array.length) {
33171 		if (typeof(trienode.__leaf) !== 'undefined') {
33172 			lastLeaf = {
33173 				consumed: i - start + 1,
33174 				value: trienode.__leaf
33175 			};
33176 		}
33177 		if (array[i] === 0) {
33178 			// null-terminator, so end the mapping.
33179 			return {
33180 				consumed: 1,
33181 				value: 0
33182 			};
33183 		} else if (typeof(trienode[array[i]]) !== 'undefined') {
33184 			// we have a mapping
33185 			if (isValue(trienode[array[i]])) {
33186 				// it is a leaf node
33187 				return {
33188 					consumed: i - start + 1,
33189 					value: trienode[array[i]]
33190 				};
33191 			} else {
33192 				// it is an intermediate node
33193     			trienode = trienode[array[i++]];
33194     		}
33195 		} else {
33196 			// no mapping for this array element, so return the last known
33197 			// leaf. If none, this will return undefined.
33198 			return lastLeaf;
33199 		}
33200 	}
33201 
33202 	return undefined;
33203 };
33204     
33205 /**
33206  * Map a string to the native character set. This string may be 
33207  * given as an intrinsic Javascript string object or an IString 
33208  * object.
33209  * 
33210  * @param {string|IString} string string to map to a different 
33211  * character set. 
33212  * @return {Uint8Array} An array of bytes representing the string 
33213  * in the native character set
33214  */
33215 CharmapTable.prototype.mapToNative = function(string) {
33216 	if (!string) {
33217 		return new Uint8Array(0);
33218 	}
33219 	
33220 	var str = (string instanceof IString) ? string : new IString(string);
33221 	
33222 	// use IString's iterator so that we take care of walking through
33223 	// the code points correctly, including the surrogate pairs
33224 	// var c, i = 0, it = str.charIterator();
33225 	var ret = new Uint8Array(str.length * this.expansionFactor);
33226 	
33227 	var i = 0, j = 0;
33228 	
33229 	while (i < string.length) {
33230 		var result = this._trieWalk(this.map.from, string, i);
33231 		if (result) {
33232 			if (result.value) {
33233     			i += result.consumed;
33234     			j += this.writeNative(ret, j, result.value);
33235 			} else {
33236 				// null-termination
33237 				i = string.length;
33238 				this.writeNative(ret, j, [result.value]);
33239 			}
33240 		} else {
33241 			// The unicode char at "i" didn't have any mapping, so
33242 			// deal with the missing char
33243 			j += this.writeNativeString(ret, j, this.dealWithMissingChar(string[i++]));
33244 		}
33245 	}
33246 
33247 	return ret.subarray(0, j);
33248 };
33249 
33250 /**
33251  * Map a native string to the standard Javascript charset of UTF-16. 
33252  * This string may be given as an array of numbers where each number 
33253  * represents a code point in the "from" charset, or as a Uint8Array 
33254  * array of bytes representing the bytes of the string in order.
33255  * 
33256  * @param {Array.<number>|Uint8Array} bytes bytes to map to 
33257  * a Unicode string
33258  * @return {string} A string in the standard Javascript charset UTF-16
33259  */
33260 CharmapTable.prototype.mapToUnicode = function(bytes) {
33261 	var ret = "";
33262 	var i = 0;
33263 	
33264 	while (i < bytes.length) {
33265 		var result = this._trieWalk(this.map.to, bytes, i);
33266 		if (result) {
33267 			if (result.value) {
33268     			i += result.consumed;
33269     			if (typeof(result.value) === 'string') {
33270         			ret += result.value;
33271         		} else if (ilib.isArray(result.value)) {
33272         			for (var j = 0; j < result.value.length; j++) {
33273         				ret += result.value[j];
33274         			}
33275         		} // else error in charmap file??
33276 			} else {
33277 				// null-termination
33278 				i = bytes.length;
33279 			}
33280 		} else {
33281 			// The byte at "i" wasn't a lead byte, so start again at the 
33282 			// next byte instead. This may synchronize the rest 
33283 			// of the string.
33284 			ret += this.dealWithMissingChar(bytes[i++]);
33285 		}
33286 	}
33287 
33288 	return ret;
33289 };
33290 
33291 Charmap._algorithms["CharmapTable"] = CharmapTable;
33292 
33293 
33294 /*< CharmapFactory.js */
33295 /*
33296  * CharmapFactory.js - Factory class to create the right subclasses of a charmap for any 
33297  * given chararacter set.
33298  * 
33299  * Copyright © 2015, JEDLSoft
33300  *
33301  * Licensed under the Apache License, Version 2.0 (the "License");
33302  * you may not use this file except in compliance with the License.
33303  * You may obtain a copy of the License at
33304  *
33305  *     http://www.apache.org/licenses/LICENSE-2.0
33306  *
33307  * Unless required by applicable law or agreed to in writing, software
33308  * distributed under the License is distributed on an "AS IS" BASIS,
33309  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
33310  *
33311  * See the License for the specific language governing permissions and
33312  * limitations under the License.
33313  */
33314 
33315 /* !depends ilib.js JSUtils.js Charmap.js CharmapTable.js */
33316 // !data charset/ISO-8859-15 charmaps/ISO-8859-15
33317 
33318 
33319 
33320 /**
33321  * Factory method to create a new instance of a character set mapping (charmap) 
33322  * subclass that is appropriate for the requested charset. Charmap instances map strings to 
33323  * other character sets. The charsets can be of any type, single-byte, multi-byte,
33324  * shifting, etc. <p>
33325  * 
33326  * All mappings are done to or from Unicode in the UTF-16 encoding, which is the base
33327  * character set and encoding used by Javascript itself. In order to convert 
33328  * between two non-Unicode character sets, you must chain two charmap instances together 
33329  * to first map to Unicode and then back to the second charset. <p>
33330  * 
33331  * The options parameter controls which mapping is constructed and its behaviours. The 
33332  * current list of supported options are:
33333  * 
33334  * <ul>
33335  * <li><i>name</i> - the name of the native charset to map to or from. This can be 
33336  * given as an {@link Charset} instance or as a string that contains any commonly used name 
33337  * for the character set, which is normalized to a standard IANA name. 
33338  * If a name is not given, this class will default to the Western European character 
33339  * set called ISO-8859-15.
33340  * 
33341  * <li><i>missing</i> - specify what to do if a mapping is missing for a particular
33342  * character. For example, if you are mapping Unicode characters to a particular native
33343  * character set that does not support particular Unicode characters, the mapper will
33344  * follow the behaviour specified in this property. Valid values are:
33345  * <ul>
33346  * <li><i>skip</i> - skip any characters that do not exist in the target charset
33347  * <li><i>placeholder</i> - put a static placeholder character in the output string 
33348  * wherever there is an unknown character in the input string. Use the <i>placeholder</i> 
33349  * parameter to specify which character to use in this case
33350  * <li><i>escape</i> - use an escape sequence to represent the unknown character 
33351  * </ul>
33352  * The default value for the missing property if not otherwise specified is "escape"
33353  * so that information is not lost.
33354  * 
33355  * <li><i>placeholder</i> - specify the placeholder character to use when the 
33356  * mapper cannot map a particular input character to the output string. If this
33357  * option is not specified, then the '?' (question mark) character is used where 
33358  * possible.
33359  * 
33360  * <li><i>escapeStyle</i> - what style of escape sequences should be used to
33361  * escape unknown characters in the input when mapping to native, and what
33362  * style of espcae sequences should be parsed when mapping to Unicode. Valid 
33363  * values are:
33364  * <ul>
33365  * <li><i>html</i> - Escape the characters as HTML entities. This would use
33366  * the standard HTML 5.0 (or later) entity names where possible, and numeric
33367  * entities in all other cases. Eg. an "e" with an acute accent would be 
33368  * "é"
33369  * <li><i>js</i> - Use the Javascript escape style. Eg. an "e" with an acute
33370  * accent would be "\u00E9". This can also be specified as "c#" as
33371  * it uses a similar escape syntax.
33372  * <li><i>c</i> - Use the C/C++ escape style, which is similar to the the
33373  * Javascript style, but uses an "x" in place of the "u". Eg. an "e" with an 
33374  * acute accent would be "\x00E9". This can also be specified as "c++".
33375  * <li><i>java</i> - Use the Java escape style. This is very similar to the
33376  * the Javascript style, but the backslash has to be escaped twice. Eg. an
33377  * "e" with an acute accent would be "\\u00E9". This can also be specified
33378  * as "ruby", as Ruby uses a similar escape syntax with double backslashes.
33379  * <li><i>perl</i> - Use the Perl escape style. Eg. an "e" with an acute
33380  * accent would be "\N{U+00E9}"
33381  * </ul>
33382  * The default if this style is not specified is "js" for Javascript.
33383  * 
33384  * <li><i>onLoad</i> - a callback function to call when this object is fully 
33385  * loaded. When the onLoad option is given, this class will attempt to
33386  * load any missing data using the ilib loader callback.
33387  * When the constructor is done (even if the data is already preassembled), the 
33388  * onLoad function is called with the current instance as a parameter, so this
33389  * callback can be used with preassembled or dynamic loading or a mix of the two.
33390  * 
33391  * <li><i>sync</i> - tell whether to load any missing data synchronously or 
33392  * asynchronously. If this option is given as "false", then the "onLoad"
33393  * callback must be given, because the instance returned from this constructor will
33394  * not be usable for a while.
33395  *
33396  * <li><i>loadParams</i> - an object containing parameters to pass to the 
33397  * loader callback function when data is missing. The parameters are not
33398  * interpretted or modified in any way. They are simply passed along. The object 
33399  * may contain any property/value pairs as long as the calling code is in
33400  * agreement with the loader callback function as to what those parameters mean.
33401  * </ul>
33402  * 
33403  * If this copy of ilib is pre-assembled and all the data is already available, 
33404  * or if the data was already previously loaded, then this constructor will call
33405  * the onLoad callback immediately when the initialization is done. 
33406  * If the onLoad option is not given, this class will only attempt to load any
33407  * missing data synchronously.
33408  * 
33409  * @static
33410  * @param {Object=} options options controlling the construction of this instance, or
33411  * undefined to use the default options
33412  * @return {Charmap|undefined} an instance of a character set mapping class appropriate for
33413  * the requested charset, or undefined if no mapper could be found that supports the
33414  * requested charset
33415  */
33416 var CharmapFactory = function(options) {
33417 	var charsetName = (options && options.name) || "ISO-8859-15";
33418 	var sync = true;
33419 	
33420 	// console.log("CharmapFactory: called with options: " + JSON.stringify(options));
33421 	
33422 	if (options) {
33423 		if (typeof(options.sync) === 'boolean') {
33424 			sync = options.sync;
33425 		}
33426 	}
33427 
33428 	var instance;
33429 	
33430 	new Charset({
33431 		name: charsetName,
33432 		sync: sync,
33433 		loadParams: options && options.loadParams,
33434 		onLoad: function (charset) {
33435 			// name will be normalized already
33436 			var cons, name = charset.getName();
33437 	
33438 			// console.log("CharmapFactory: normalized charset name: " + name);
33439 			
33440 			if (!Charmap._algorithms[name] && ilib.isDynCode()) {
33441 				// console.log("CharmapFactory: isDynCode. Doing require");
33442 				var entry = CharmapFactory._dynMap[name] || "CharmapTable";
33443 				cons = Charmap._algorithms[name] = require("./" + entry + ".js");
33444 			}
33445 			
33446 			if (!cons) {
33447 				cons = Charmap._algorithms[name] || Charmap._algorithms["CharmapTable"];
33448 			}
33449 			
33450 			// console.log("CharmapFactory: cons is "); console.dir(cons);
33451 			
33452 			// pass the same options through to the constructor so the subclass
33453 			// has the ability to do something with if it needs to
33454 			instance = cons && new cons(JSUtils.merge(options || {}, {charset: charset}));
33455 		}
33456 	});
33457 	
33458 	return instance;
33459 };
33460 
33461 
33462 /**
33463  * Map standardized charset names to classes to initialize in the dynamic code model.
33464  * These classes implement algorithmic mappings instead of table-based ones.
33465  * TODO: Need to figure out some way that this doesn't have to be updated by hand.
33466  * @private
33467  */
33468 CharmapFactory._dynMap = {
33469 	"UTF-8":      "UTF8",
33470 	"UTF-16":     "UTF16LE",
33471 	"UTF-16LE":   "UTF16LE",
33472 	"UTF-16BE":   "UTF16BE",
33473 	"US-ASCII":   "Charmap"
33474 	/*
33475 	not implemented yet
33476 	"ISO-2022-JP": "ISO2022",
33477 	"ISO-2022-JP-1": "ISO2022",
33478 	"ISO-2022-JP-2": "ISO2022",
33479 	"ISO-2022-JP-3": "ISO2022",
33480 	"ISO-2022-JP-2004": "ISO2022",
33481 	"ISO-2022-CN": "ISO2022",
33482 	"ISO-2022-CN-EXT": "ISO2022",
33483 	"ISO-2022-KR": "ISO2022"
33484 	*/
33485 };
33486 
33487 
33488 /*< UTF8.js */
33489 /*
33490  * UTF8.js - Implement Unicode Transformation Format 8-bit mappings
33491  * 
33492  * Copyright © 2014-2015, JEDLSoft
33493  *
33494  * Licensed under the Apache License, Version 2.0 (the "License");
33495  * you may not use this file except in compliance with the License.
33496  * You may obtain a copy of the License at
33497  *
33498  *     http://www.apache.org/licenses/LICENSE-2.0
33499  *
33500  * Unless required by applicable law or agreed to in writing, software
33501  * distributed under the License is distributed on an "AS IS" BASIS,
33502  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
33503  *
33504  * See the License for the specific language governing permissions and
33505  * limitations under the License.
33506  */
33507 
33508 // !depends Charmap.js IString.js
33509 
33510 // !data charset/UTF-8
33511 
33512 
33513 /**
33514  * @class
33515  * Create a new UTF-8 mapping instance
33516  * @constructor
33517  * @extends Charmap
33518  */
33519 var UTF8 = function (options) {
33520 	this.charset = new Charset({name: "UTF-8"});
33521 };
33522 
33523 UTF8.prototype = new Charmap();
33524 UTF8.prototype.parent = Charmap;
33525 UTF8.prototype.constructor = UTF8;
33526 
33527 UTF8.prototype.validate = function(bytes) {
33528 	var i = 0;
33529 	while (i < bytes.length) {
33530 		if ((bytes[i] & 0x80) === 0) {
33531 			i++;
33532 		} else {
33533 			var len;
33534 			if ((bytes[i] & 0xC0) === 0xC0) {
33535 				len = 2;
33536 			} else if ((bytes[i] & 0xE0) === 0xE0) {
33537 				len = 3;
33538 			} else if ((bytes[i] & 0xF0) === 0xF0) {
33539 				len = 4;
33540 			} else {
33541 				// invalid lead byte
33542 				return false;
33543 			}
33544 			if (i + len > bytes.length) {
33545 				// not enough trailing bytes
33546 				return false;
33547 			}
33548 			for (var j = 1; j < len; j++) {
33549 				// check each trailing byte to see if it has the correct form
33550 				if ((bytes[i+j] & 0x80) !== 0x80) {
33551 					return false;
33552 				}
33553 			}
33554 			i += len;
33555 		}
33556 	}
33557 	
33558 	return true;
33559 };
33560 	
33561 UTF8.prototype.mapToUnicode = function (bytes) {
33562 	if (typeof(Buffer) !== "undefined") {
33563 		// nodejs can convert it quickly in native code
33564 		var b = new Buffer(bytes);
33565 		return b.toString("utf8");
33566 	}
33567 	// otherwise we have to implement it in pure JS
33568 	var ret = "";
33569 	var i = 0;
33570 	while (i < bytes.length) {
33571 		if (bytes[i] === 0) {
33572 			// null-terminator
33573 			i = bytes.length;
33574 		} else if ((bytes[i] & 0x80) === 0) {
33575 			// 1 byte char
33576 			ret += String.fromCharCode(bytes[i++]);
33577 		} else if ((bytes[i] & 0xE0) === 0xC0) {
33578 			// 2 byte char
33579 			if (i + 1 >= bytes.length || (bytes[i+1] & 0x80) !== 0x80) {
33580 				throw "invalid utf-8 bytes";
33581 			}
33582 			// xxx xxyyyyyy
33583 			ret += String.fromCharCode((bytes[i] & 0x1F) << 6 | (bytes[i+1] & 0x3F));
33584 			i += 2;
33585 		} else if ((bytes[i] & 0xF0) === 0xE0) {
33586 			// 3 byte char
33587 			if (i + 2 >= bytes.length || (bytes[i+1] & 0x80) !== 0x80 || (bytes[i+2] & 0x80) !== 0x80) {
33588 				throw "invalid utf-8 bytes";
33589 			}
33590 			// xxxxyyyy yyzzzzzz
33591 			ret += String.fromCharCode((bytes[i] & 0xF) << 12 | (bytes[i+1] & 0x3F) << 6 | (bytes[i+2] & 0x3F));
33592 			i += 3;
33593 		} else if ((bytes[i] & 0xF8) === 0xF0) {
33594 			// 4 byte char
33595 			if (i + 3 >= bytes.length || (bytes[i+1] & 0x80) !== 0x80 || (bytes[i+2] & 0x80) !== 0x80 || (bytes[i+3] & 0x80) !== 0x80) {
33596 				throw "invalid utf-8 bytes";
33597 			}
33598 			// wwwxx xxxxyyyy yyzzzzzz
33599 			ret += IString.fromCodePoint((bytes[i] & 0x7) << 18 | (bytes[i+1] & 0x3F) << 12 | (bytes[i+2] & 0x3F) << 6 | (bytes[i+3] & 0x3F));
33600 			i += 4;
33601 		} else {
33602 			throw "invalid utf-8 bytes";
33603 		}
33604 	}
33605 	
33606 	return ret;
33607 };
33608 	
33609 UTF8.prototype.mapToNative = function(str) {
33610 	if (typeof(Buffer) !== "undefined") {
33611 		// nodejs can convert it quickly in native code
33612 		var b = new Buffer(str, "utf8");
33613 		return new Uint8Array(b);
33614 	}
33615 	// otherwise we have to implement it in pure JS
33616 	var istr = (str instanceof IString) ? str : new IString(str);
33617 	
33618 	// step through the surrogate pairs as single code points by using
33619 	// IString's iterator 
33620 	var it = istr.iterator();
33621 	
33622 	// multiply by 4 because the max size of a UTF-8 char is 4 bytes, so
33623 	// this will at least get us enough room to encode everything. Add 1
33624 	// for the null terminator
33625 	var ret = new Uint8Array(istr.length * 4 + 1);
33626 	var i = 0;
33627 	
33628 	while (it.hasNext()) {
33629 		var c = it.next();
33630 		if (c > 0x7F) {
33631 			if (c > 0x7FF) {
33632 				if (c > 0xFFFF) {
33633 					// astral planes char
33634 					ret[i]   = 0xF0 | ((c >> 18) & 0x3);
33635 					ret[i+1] = 0x80 | ((c >> 12) & 0x3F);
33636 					ret[i+2] = 0x80 | ((c >> 6) & 0x3F);
33637 					ret[i+3] = 0x80 | (c & 0x3F);
33638 					
33639 					i += 4;
33640 				} else {
33641 					ret[i]   = 0xE0 | ((c >> 12) & 0xF);
33642 					ret[i+1] = 0x80 | ((c >> 6) & 0x3F);
33643 					ret[i+2] = 0x80 | (c & 0x3F);
33644 					
33645 					i += 3;
33646 				}
33647 			} else {
33648 				ret[i]   = 0xC0 | ((c >> 6) & 0x1F);
33649 				ret[i+1] = 0x80 | (c & 0x3F);
33650 				
33651 				i += 2;
33652 			}
33653 		} else {
33654 			ret[i++] = (c & 0x7F);
33655 		}
33656 	}
33657 	ret[i] = 0; // null-terminate it
33658 	
33659 	return ret;
33660 };
33661 
33662 Charmap._algorithms["UTF-8"] = UTF8;
33663 
33664 
33665 /*< UTF16BE.js */
33666 /*
33667  * UTF16BE.js - Implement Unicode Transformation Format 16-bit,
33668  * Big Endian mappings
33669  * 
33670  * Copyright © 2014-2015, JEDLSoft
33671  *
33672  * Licensed under the Apache License, Version 2.0 (the "License");
33673  * you may not use this file except in compliance with the License.
33674  * You may obtain a copy of the License at
33675  *
33676  *     http://www.apache.org/licenses/LICENSE-2.0
33677  *
33678  * Unless required by applicable law or agreed to in writing, software
33679  * distributed under the License is distributed on an "AS IS" BASIS,
33680  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
33681  *
33682  * See the License for the specific language governing permissions and
33683  * limitations under the License.
33684  */
33685 
33686 // !depends Charmap.js
33687 
33688 // !data charset/UTF-16 charset/UTF-16BE
33689 
33690 
33691 /**
33692  * @class
33693  * Create a new UTF-16BE mapping instance
33694  * @constructor
33695  * @extends Charmap
33696  */
33697 var UTF16BE = function (options) {
33698 	this.charset = new Charset({name: "UTF-16BE"});
33699 };
33700 
33701 UTF16BE.prototype = new Charmap();
33702 UTF16BE.prototype.parent = Charmap;
33703 UTF16BE.prototype.constructor = UTF16BE;
33704 
33705 UTF16BE.prototype.mapToUnicode = function (bytes) {
33706 	// nodejs can't convert big-endian in native code,
33707 	// so we would have to flip each Uint16 ourselves.
33708 	// At that point, it's just quicker to convert 
33709 	// in JS code anyways
33710 	var ret = "";
33711 	for (var i = 0; i < bytes.length; i += 2) {
33712 		ret += String.fromCharCode(bytes[i] << 8 | bytes[i+1]);
33713 	}
33714 	
33715 	return ret;
33716 };
33717 	
33718 UTF16BE.prototype.mapToNative = function(str) {
33719 	// nodejs can't convert big-endian in native code,
33720 	// so we would have to flip each Uint16 ourselves.
33721 	// At that point, it's just quicker to convert 
33722 	// in JS code anyways
33723 	var ret = new Uint8Array(str.length * 2 + 2);
33724 	var c;
33725 	for (var i = 0; i < str.length; i++) {
33726 		c = str.charCodeAt(i);
33727 		ret[i*2] = (c >> 8) & 0xFF;
33728 		ret[i*2+1] = c & 0xFF;
33729 	}
33730 	// double null terminate it, just in case
33731 	ret[i*2+1] = 0;
33732 	ret[i*2+2] = 0;
33733 	
33734 	return ret;
33735 };
33736 
33737 Charmap._algorithms["UTF-16BE"] = UTF16BE;
33738 
33739 
33740 /*< UTF16LE.js */
33741 /*
33742  * UTF16LE.js - Implement Unicode Transformation Format 16 bit, 
33743  * Little Endian mappings
33744  * 
33745  * Copyright © 2014-2015, JEDLSoft
33746  *
33747  * Licensed under the Apache License, Version 2.0 (the "License");
33748  * you may not use this file except in compliance with the License.
33749  * You may obtain a copy of the License at
33750  *
33751  *     http://www.apache.org/licenses/LICENSE-2.0
33752  *
33753  * Unless required by applicable law or agreed to in writing, software
33754  * distributed under the License is distributed on an "AS IS" BASIS,
33755  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
33756  *
33757  * See the License for the specific language governing permissions and
33758  * limitations under the License.
33759  */
33760 
33761 // !depends Charmap.js
33762 
33763 // !data charset/UTF-16 charset/UTF-16LE
33764 
33765 
33766 /**
33767  * @class
33768  * Create a new UTF-16LE mapping instance
33769  * @constructor
33770  * @extends Charmap
33771  */
33772 var UTF16LE = function (options) {
33773 	this.charset = new Charset({name: "UTF-16LE"});
33774 };
33775 
33776 UTF16LE.prototype = new Charmap();
33777 UTF16LE.prototype.parent = Charmap;
33778 UTF16LE.prototype.constructor = UTF16LE;
33779 
33780 UTF16LE.prototype.mapToUnicode = function (bytes) {
33781 	if (typeof(Buffer) !== "undefined") {
33782 		// nodejs can convert it quickly in native code
33783 		var b = new Buffer(bytes);
33784 		return b.toString("utf16le");
33785 	}
33786 	// otherwise we have to implement it in pure JS
33787 	var ret = "";
33788 	for (var i = 0; i < bytes.length; i += 2) {
33789 		ret += String.fromCharCode(bytes[i+1] << 8 | bytes[i]);
33790 	}
33791 	
33792 	return ret;
33793 };
33794 	
33795 UTF16LE.prototype.mapToNative =  function(str) {
33796 	if (typeof(Buffer) !== "undefined") {
33797 		// nodejs can convert it quickly in native code
33798 		var b = new Buffer(str, "utf16le");
33799 		return new Uint8Array(b);
33800 	}
33801 	// otherwise we have to implement it in pure JS
33802 	var ret = new Uint8Array(str.length * 2 + 2);
33803 	var c;
33804 	for (var i = 0; i < str.length; i++) {
33805 		c = str.charCodeAt(i);
33806 		ret[i*2] = c & 0xFF;
33807 		ret[i*2+1] = (c >> 8) & 0xFF;
33808 	}
33809 	// double null terminate it, just in case
33810 	ret[i*2+1] = 0;
33811 	ret[i*2+2] = 0;
33812 	
33813 	return ret;
33814 };
33815 
33816 Charmap._algorithms["UTF-16"] = UTF16LE;
33817 Charmap._algorithms["UTF-16LE"] = UTF16LE;
33818 
33819 
33820 /*< /mnt/Terasaur/root/home/edwin/src/ilib-sf-trunk/js/lib/ilib-full-inc.js */
33821 /**
33822  * @license
33823  * Copyright © 2012-2015, JEDLSoft
33824  *
33825  * Licensed under the Apache License, Version 2.0 (the "License");
33826  * you may not use this file except in compliance with the License.
33827  * You may obtain a copy of the License at
33828  *
33829  *     http://www.apache.org/licenses/LICENSE-2.0
33830  *
33831  * Unless required by applicable law or agreed to in writing, software
33832  * distributed under the License is distributed on an "AS IS" BASIS,
33833  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
33834  *
33835  * See the License for the specific language governing permissions and
33836  * limitations under the License.
33837  */
33838 
33839 /*
33840  * ilib-full-inc.js - metafile that includes all other js files
33841  */
33842 
33843 /* !depends
33844 ilib.js
33845 DateRngFmt.js
33846 IDate.js
33847 DateFactory.js
33848 HebrewDate.js
33849 HebrewCal.js
33850 IslamicCal.js
33851 IslamicDate.js
33852 JulianCal.js
33853 JulianDate.js
33854 GregorianCal.js
33855 GregorianDate.js
33856 ThaiSolarCal.js
33857 ThaiSolarDate.js
33858 PersianCal.js
33859 PersianDate.js
33860 PersianAlgoCal.js
33861 PersianAlgoDate.js
33862 HanCal.js
33863 HanDate.js
33864 EthiopicCal.js
33865 EthiopicDate.js
33866 CopticCal.js
33867 CopticDate.js
33868 INumber.js
33869 NumFmt.js
33870 JulianDay.js
33871 DateFmt.js
33872 Calendar.js
33873 CalendarFactory.js
33874 Utils.js
33875 Locale.js
33876 IString.js
33877 DurationFmt.js
33878 ResBundle.js
33879 CType.js
33880 LocaleInfo.js
33881 DateRngFmt.js
33882 isAlnum.js
33883 isAlpha.js
33884 isAscii.js
33885 isBlank.js
33886 isCntrl.js
33887 isDigit.js
33888 isGraph.js
33889 isIdeo.js
33890 isLower.js
33891 isPrint.js
33892 isPunct.js
33893 isSpace.js
33894 isUpper.js
33895 isXdigit.js
33896 isScript.js
33897 ScriptInfo.js
33898 Name.js
33899 NameFmt.js
33900 Address.js
33901 AddressFmt.js
33902 Collator.js
33903 nfkc/all.js
33904 LocaleMatcher.js
33905 NormString.js
33906 CaseMapper.js
33907 GlyphString.js
33908 PhoneFmt.js
33909 PhoneGeoLocator.js
33910 PhoneNumber.js
33911 Measurement.js
33912 MeasurementFactory.js
33913 UnitFmt.js
33914 LengthUnit.js
33915 VelocityUnit.js
33916 DigitalStorageUnit.js
33917 TemperatureUnit.js
33918 UnknownUnit.js
33919 TimeUnit.js
33920 MassUnit.js
33921 AreaUnit.js
33922 FuelConsumptionUnit.js
33923 VolumeUnit.js	
33924 EnergyUnit.js
33925 Charset.js
33926 Charmap.js
33927 CharmapFactory.js
33928 CharmapTable.js
33929 UTF8.js
33930 UTF16BE.js
33931 UTF16LE.js
33932 */
33933 
33934